From 79ecf9cd6a9d52001d9baa77b84b3290497dfeb8 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Tue, 3 Oct 2017 08:17:58 +0200 Subject: [PATCH 01/21] Allow punch out time to be null - fix for mysql strict date mode --- migrations/list.php | 1 + ...v20171001_200201_update_attendance_out.php | 23 +++++++++++++++++++ .../User/Api/AttendanceActionManager.php | 1 - 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 migrations/v20171001_200201_update_attendance_out.php diff --git a/migrations/list.php b/migrations/list.php index 3cea4f46..7a8e0c1a 100644 --- a/migrations/list.php +++ b/migrations/list.php @@ -1,5 +1,6 @@ executeQuery($sql); + } + + public function down(){ + $sql = <<<'SQL' + alter table Attendance modify column `out_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'; +SQL; + + return $this->executeQuery($sql); + } + +} + diff --git a/src/Attendance/User/Api/AttendanceActionManager.php b/src/Attendance/User/Api/AttendanceActionManager.php index a5c466f7..39730f65 100644 --- a/src/Attendance/User/Api/AttendanceActionManager.php +++ b/src/Attendance/User/Api/AttendanceActionManager.php @@ -135,7 +135,6 @@ class AttendanceActionManager extends SubActionManager $this->baseService->audit(IceConstants::AUDIT_ACTION, "Punch Out \ time:".$openPunch->out_time); } else { $openPunch->in_time = $dateTime; - $openPunch->out_time = '0000-00-00 00:00:00'; $openPunch->note = $req->note; $openPunch->image_in = $req->image; $openPunch->employee = $employee->id; From 8d86b3c371a52b59cc1258ce38897cd51b8cd350 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 8 Oct 2017 16:48:54 +0200 Subject: [PATCH 02/21] Data import module added to open source --- admin/data/LICENSE.txt | 44 ++++++++++ admin/data/README.txt | 7 ++ admin/data/index.php | 19 +++++ admin/data/lib.js | 177 +++++++++++++++++++++++++++++++++++++++++ admin/data/meta.json | 12 +++ 5 files changed, 259 insertions(+) create mode 100644 admin/data/LICENSE.txt create mode 100644 admin/data/README.txt create mode 100644 admin/data/index.php create mode 100644 admin/data/lib.js create mode 100644 admin/data/meta.json diff --git a/admin/data/LICENSE.txt b/admin/data/LICENSE.txt new file mode 100644 index 00000000..5fb38ea8 --- /dev/null +++ b/admin/data/LICENSE.txt @@ -0,0 +1,44 @@ +ICEHRM END USER LICENSE AGREEMENT +NOTICE TO ALL USERS: BY PURCHASING THE MODULE, YOU (EITHER AN INDIVIDUAL OR A SINGLE ENTITY) CONSENT TO BE BOUND BY AND BECOME A PARTY TO THIS AGREEMENT. + +All references to "Software" herein shall be deemed to include the software license with which you will be provided by Gamonoid Media Pvt Ltd, as part of the Software. + +1. LICENSE GRANT. Subject to the payment of the applicable licence fees, and subject to the terms and conditions of this Agreement, ICEHRM hereby grants to you a non-exclusive, non-transferable right to use one copy of the specified version of the Software and the accompanying documentation (the "Documentation") for the term of this Agreement solely for your own internal business purposes. You may install one copy of the Software for production use. +. +2. USE. The Software is licensed as a single product; it may not be used on more than one ICEHRM Server at a time. The Software is "in use" on a Server when its installed on a Server. You shall not, nor permit any third party to copy (other than as expressly permitted herein). You shall not rent, lease or lend the Software to any other person, nor transfer or sub-licence your licence rights to any other person. + +3. TERM. This Agreement is effective until terminated as set forth herein. This Agreement will terminate automatically if you fail to comply with any of the conditions, limitations or other requirements described herein. Upon any termination of this Agreement, you must immediately destroy all copies of the Software and the Documentation. You may terminate this Agreement at any point by destroying all copies of the Software and the Documentation. + +4. SUPPORT. Gamonoid Media Pvt Ltd will provide you support according to the support agreement subscribed by the company. + +5. OWNERSHIP RIGHTS. The Software is protected by copyright laws. ICEHRM and Gamonoid Media Pvt Ltd own and retain all right, title and interest in and to the Software, including all copyrights, patents, trademarks and other intellectual property rights therein. Your possession, installation, or use of the Software does not transfer to you any title to the intellectual property in the Software, and you will not acquire any rights to the Software except as expressly set forth in this Agreement. + +6. LIMITED WARRANTY. You may not rent, lease, loan or resell the Software. You may not permit third parties to benefit from the use or functionality of the Software via a timesharing, service bureau or other arrangement, except to the extent such use is specified in the applicable list price or product packaging for the Software. You may not transfer any of the rights granted to you under this Agreement. You may not modify, or create derivative works based upon, the Software in whole or in part. You may not copy the Software or Documentation except as expressly permitted in Section 1 above. You may not remove any proprietary notices or labels on the Software. All rights not expressly set forth hereunder are reserved by ICEHRM. ICEHRM reserves the right to periodically conduct audits upon advance written notice to verify compliance with the terms of this Agreement. + +7. WARRANTY and DISCLAIMER. + +(i) Gamonoid Media Pvt Ltd. warrants that for 30 days from first download or installation the Software will perform substantially in accordance with the functionality described in the Documentation (http://blog.icehrm.com) when operated properly and in the manner specified in the Documentation. + +(ii) You accept all responsibility for the selection of this Software to meet your requirements. + +(iii) Gamonoid Media Pvt Ltd. does not warrant that the Software and/or the Documentation will be suitable for such requirements nor that any use will be uninterrupted and error free. + +(iv) The warranty in (i) shall not apply if you (a) make or cause to be made any modifications to this Software, (b) use the Software in a manner for which it was not intended or (c) use the Software other than as permitted under this Agreement. + +(vii) The warranties and conditions stated in this Agreement are in lieu of all other conditions, warranties or other terms concerning the supply or purported supply of, failure to supply or delay in supplying the Software or the Documentation which might but for this paragraph (vii) have effect between the ICEHRM and you or would otherwise be implied into or incorporated into this Agreement or any collateral contract, whether by statute, common law or otherwise, all of which are hereby excluded (including, without limitation, the implied conditions, warranties or other terms as to satisfactory quality, fitness for purpose or as to the use of reasonable skill and care). + +8. LIMITATION of LIABILITY. Gamonoid Media Pvt Ltd. shall have no liability (whether in contract, tort, restitution or otherwise) for any of the following losses or damage (whether such losses or damage were foreseen, foreseeable, known or otherwise): +- Loss of revenue; +- Loss of actual or anticipated profits (including for loss of profits on contracts); +- Loss of the use of money; +- Loss of anticipated savings; +- Loss of business; +- Loss of opportunity; +- Loss of goodwill; +- Loss of reputation; +- Loss of, damage to or corruption of data; +or +Any indirect or consequential loss or damage howsoever caused (including, for the avoidance of doubt, where such loss or damage is of the type specified in paragraph (ii), (a) to (ii), (i). +The ICEHRM liability (whether in contract, tort, restitution or otherwise) arising out of or in connection with the supply of the Software shall in no circumstances exceed a sum equal to the amount equally paid by you for the Software. +The construction and interpretation of this Agreement shall be governed in accordance with the laws of Sri Lanka. The parties hereby submit to the jurisdiction of the courts of Sri Lanka save that ICEHRM as claimant shall be entitled to initiate proceedings in any court of competent jurisdiction. +This Agreement contains the entire understanding of the parties with respect to the subject matter hereof and supersedes all and any prior understandings, undertakings and promises between you and ICEHRM, whether oral or in writing, which have been given or may be implied from anything written or said in negotiations between us or our representatives prior to this Agreement and all prior agreements between the parties relating to the matters aforesaid shall cease to have effect as from the Effective Date. \ No newline at end of file diff --git a/admin/data/README.txt b/admin/data/README.txt new file mode 100644 index 00000000..0bd0cec8 --- /dev/null +++ b/admin/data/README.txt @@ -0,0 +1,7 @@ +This module is licensed under IceHrm Commercial License, which can be found in LICENSE.txt. +You are allowed to make any modification required to these module, but only allowed to use +the module in one production server (even with modifications). + +Installation +------------ +Copy this module into /admin/ directory \ No newline at end of file diff --git a/admin/data/index.php b/admin/data/index.php new file mode 100644 index 00000000..1feb2dce --- /dev/null +++ b/admin/data/index.php @@ -0,0 +1,19 @@ +addModuleOrGroup(new \Classes\ModuleBuilder\ModuleTab( + 'DataImport','DataImport','Data Importers','DataImportAdapter','','',true +)); +$moduleBuilder->addModuleOrGroup(new \Classes\ModuleBuilder\ModuleTab( + 'DataImportFile','DataImportFile','Data Import Files','DataImportFileAdapter','','' +)); + +echo \Classes\UIManager::getInstance()->renderModule($moduleBuilder); + +include APP_BASE_PATH.'footer.php'; diff --git a/admin/data/lib.js b/admin/data/lib.js new file mode 100644 index 00000000..a6a91e72 --- /dev/null +++ b/admin/data/lib.js @@ -0,0 +1,177 @@ +/** + * Author: Thilina Hasantha + */ + +/** + * DataImportAdapter + */ + +function DataImportAdapter(endPoint,tab,filter,orderBy) { + this.initAdapter(endPoint,tab,filter,orderBy); +} + +DataImportAdapter.inherits(AdapterBase); + + + +DataImportAdapter.method('getDataMapping', function() { + return [ + "id", + "name", + "dataType", + "details" + ]; +}); + +DataImportAdapter.method('getHeaders', function() { + return [ + { "sTitle": "ID" ,"bVisible":false}, + { "sTitle": "Name" }, + { "sTitle": "Data Type" }, + { "sTitle": "Details" } + ]; +}); + +DataImportAdapter.method('getFormFields', function() { + return [ + [ "id", {"label":"ID","type":"hidden"}], + [ "name", {"label":"Name","type":"text","validation":""}], + [ "dataType", {"label":"Data Type","type":"text","validation":""}], + [ "details", {"label":"Details","type":"textarea","validation":"none"}], + [ "columns", {"label":"Columns","type":"datagroup", + "form":[ + [ "name", {"label":"Name","type":"text","validation":""}], + [ "title", {"label":"Filed Title","type":"text","validation":"none"}], + [ "type", {"label":"Type","type":"select","sort": "none","source":[["Normal","Normal"],["Reference","Reference"],["Attached","Attached"]]}], + [ "dependOn", {"label":"Depends On","type":"select","allow-null":true,"null-label":"N/A","source":[["EmergencyContact","Emergency Contacts"],["Ethnicity","Ethnicity"],["Nationality","Nationality"],["JobTitle","JobTitle"],["PayFrequency","PayFrequency"],["PayGrade","PayGrade"],["EmploymentStatus","EmploymentStatus"],["CompanyStructure","CompanyStructure"],["Employee","Employee"]]}], + [ "dependOnField", {"label":"Depends On Field","type":"text","validation":"none"}], + [ "isKeyField", {"label":"Is Key Field","type":"select","validation":"","source":[["No","No"],["Yes","Yes"]]}], + [ "idField", {"label":"Is ID Field","type":"select","validation":"","source":[["No","No"],["Yes","Yes"]]}] + ], + "html":'
#_name_# #_delete_##_edit_#
Header Title: #_title_#
Type: #_type_#
', + "validation":"none", + "custom-validate-function":function (data){ + var res = {}; + res['params'] = data; + res['valid'] = true; + if(data.type == 'Reference'){ + if(data.dependOn == "NULL"){ + res['message'] = "If the type is Reference this field should referring another table"; + res['valid'] = false; + }else if(dependOnField == null || dependOnField == undefined){ + res['message'] = "If the type is Reference then 'Depends On Field' can not be empty"; + res['valid'] = false; + } + } + + return res; + } + + }], + ]; +}); + + +/** + * DataImportFileAdapter + */ + +function DataImportFileAdapter(endPoint,tab,filter,orderBy) { + this.initAdapter(endPoint,tab,filter,orderBy); +} + +DataImportFileAdapter.inherits(AdapterBase); + + + +DataImportFileAdapter.method('getDataMapping', function() { + return [ + "id", + "name", + "data_import_definition", + "status" + ]; +}); + +DataImportFileAdapter.method('getHeaders', function() { + return [ + { "sTitle": "ID" ,"bVisible":false}, + { "sTitle": "Name" }, + { "sTitle": "Data Import Definition" }, + { "sTitle": "Status" } + ]; +}); + +DataImportFileAdapter.method('getFormFields', function() { + return [ + [ "id", {"label":"ID","type":"hidden"}], + [ "name", {"label":"Name","type":"text","validation":""}], + [ "data_import_definition", {"label":"Data Import Definitions","type":"select","remote-source":["DataImport","id","name"]}], + [ "file", {"label":"File to Import","type":"fileupload","validation":"","filetypes":"csv,txt"}], + [ "details", {"label":"Last Export Result","type":"textarea","validation":"none"}] + ]; +}); + +DataImportFileAdapter.method('getActionButtonsHtml', function(id,data) { + var editButton = ''; + var processButton = ''; + var deleteButton = ''; + var cloneButton = ''; + + var html = '
_edit__process__clone__delete_
'; + + + if(this.showAddNew){ + html = html.replace('_clone_',cloneButton); + }else{ + html = html.replace('_clone_',''); + } + + if(this.showDelete){ + html = html.replace('_delete_',deleteButton); + }else{ + html = html.replace('_delete_',''); + } + + if(this.showEdit){ + html = html.replace('_edit_',editButton); + }else{ + html = html.replace('_edit_',''); + } + + if (data[3] == 'Not Processed') { + html = html.replace('_process_',processButton); + } else { + html = html.replace('_process_',''); + } + + + + html = html.replace(/_id_/g,id); + html = html.replace(/_status_/g,data[6]); + html = html.replace(/_BASE_/g,this.baseUrl); + return html; +}); + + +DataImportFileAdapter.method('process', function(id) { + var that = this; + var object = {"id":id}; + var reqJson = JSON.stringify(object); + + var callBackData = []; + callBackData['callBackData'] = []; + callBackData['callBackSuccess'] = 'processSuccessCallBack'; + callBackData['callBackFail'] = 'processFailCallBack'; + + this.customAction('processDataFile','admin=data',reqJson,callBackData); +}); + +DataImportFileAdapter.method('processSuccessCallBack', function(callBackData) { + this.showMessage("Success", "File imported successfully."); +}); + + +DataImportFileAdapter.method('processFailCallBack', function(callBackData) { + this.showMessage("Error", "File import unsuccessful. Result:"+callBackData); +}); diff --git a/admin/data/meta.json b/admin/data/meta.json new file mode 100644 index 00000000..9dfc0e51 --- /dev/null +++ b/admin/data/meta.json @@ -0,0 +1,12 @@ +{ + "label": "Data", + "menu": "System", + "order": "8", + "icon": "fa-database", + "user_levels": [ + "Admin" + ], + "permissions": [], + "model_namespace": "\\Data\\Common\\Model", + "manager": "\\Data\\Admin\\Api\\DataAdminManager" +} \ No newline at end of file From 9f7831bafe628932a9a7cdb207518752c4908b7d Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 8 Oct 2017 16:51:05 +0200 Subject: [PATCH 03/21] Order payroll columns by calculation group --- admin/payroll/index.php | 2 +- admin/payroll/lib.js | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/admin/payroll/index.php b/admin/payroll/index.php index ddccd7e8..2f5d348f 100644 --- a/admin/payroll/index.php +++ b/admin/payroll/index.php @@ -109,7 +109,7 @@ include APP_BASE_PATH.'modulejslibs.inc.php'; modJsList['tabPayrollData'].setColumnFieldName('payroll_item'); modJsList['tabPayrollData'].setTables('PayrollEmployee','PayrollColumn','PayrollData'); - modJsList['tabPayrollColumn'] = new PayrollColumnAdapter('PayrollColumn','PayrollColumn','','name, colorder'); + modJsList['tabPayrollColumn'] = new PayrollColumnAdapter('PayrollColumn','PayrollColumn','','deduction_group, colorder'); modJsList['tabPayrollColumn'].setRemoteTable(true); //modJsList['tabPayrollColumnTemplate'] = new PayrollColumnTemplateAdapter('PayrollColumnTemplate','PayrollColumnTemplate'); diff --git a/admin/payroll/lib.js b/admin/payroll/lib.js index b3ce4a8b..5a5752bd 100644 --- a/admin/payroll/lib.js +++ b/admin/payroll/lib.js @@ -297,6 +297,7 @@ PayrollColumnAdapter.method('getDataMapping', function() { "name", "colorder", "calculation_hook", + "deduction_group", "editable", "enabled" ]; @@ -308,6 +309,7 @@ PayrollColumnAdapter.method('getHeaders', function() { { "sTitle": "Name"}, { "sTitle": "Column Order"}, { "sTitle": "Calculation Method"}, + { "sTitle": "Calculation Group"}, { "sTitle": "Editable"}, { "sTitle": "Enabled"} ]; @@ -334,6 +336,7 @@ PayrollColumnAdapter.method('getFormFields', function() { [ "id", {"label":"ID","type":"hidden"}], [ "name", {"label":"Name","type":"text","validation":""}], [ "calculation_hook", {"label":"Predefined Calculations","type":"select2","allow-null":true,"null-label":"None","remote-source":["CalculationHook","code","name"]}], + [ "deduction_group", {"label":"Calculation Group","type":"select2","allow-null":true,"null-label":"Common","remote-source":["DeductionGroup","id","name"]}], [ "salary_components", {"label":"Salary Components","type":"select2multi","remote-source":["SalaryComponent","id","name"]}], [ "deductions", {"label":"Calculation Method","type":"select2multi","remote-source":["Deduction","id","name"]}], [ "add_columns", {"label":"Columns to Add","type":"select2multi","remote-source":["PayrollColumn","id","name"]}], @@ -347,6 +350,12 @@ PayrollColumnAdapter.method('getFormFields', function() { ]; }); +PayrollColumnAdapter.method('getFilters', function() { + return [ + [ "deduction_group", {"label":"Calculation Group","type":"select2","allow-null":true,"null-label":"Any","remote-source":["DeductionGroup","id","name"]}] + ]; +}); + From 10403e280cced7e5f08bef1ee717587506aa9a90 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 8 Oct 2017 16:52:10 +0200 Subject: [PATCH 04/21] Add export tab to admin reports --- admin/reports/index.php | 26 ++++++++++++++++++-------- admin/reports/lib.js | 14 +++++++------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/admin/reports/index.php b/admin/reports/index.php index d93847be..22ef8233 100644 --- a/admin/reports/index.php +++ b/admin/reports/index.php @@ -1,38 +1,48 @@ -
- + - +
- +
+
+
+
+ +
- + diff --git a/admin/reports/lib.js b/admin/reports/lib.js index 989e8716..ccfdceac 100644 --- a/admin/reports/lib.js +++ b/admin/reports/lib.js @@ -78,17 +78,17 @@ ReportAdapter.method('processFormFieldsWithObject', function(object) { that.remoteFieldsExists = true; } }); - + } } - + var tempArray = []; that._formFileds.forEach(function(entry) { if(jQuery.inArray(entry[0], fieldsToDelete) < 0){ tempArray.push(entry); } }); - + that._formFileds = tempArray; }); @@ -107,7 +107,7 @@ ReportAdapter.method('renderForm', function(object) { } this.currentReport = object; - + }); ReportAdapter.method('renderFormNew', function(object) { @@ -284,8 +284,8 @@ ReportAdapter.method('addSuccessCallBack', function(callBackData,serverData) { link = 'Download Report '; } link = link.replace(/_BASE_/g,this.baseUrl); - - if(this.currentReport.output == "PDF"){ + + if(this.currentReport.output == "PDF" || this.currentReport.output == "JSON"){ this.showMessage("Download Report",link); @@ -352,7 +352,7 @@ ReportAdapter.method('fillForm', function(object) { }else{ $("#"+this.getTableName()+'Form #'+fields[i][0]).val(object[fields[i][0]]); } - + } }); From ddb46d8443dc5fb5922e7457a8bf3ed89fe0c189 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 8 Oct 2017 16:53:33 +0200 Subject: [PATCH 05/21] Fix zero time issue when updating time sheets --- modules/time_sheets/lib.js | 110 ++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/modules/time_sheets/lib.js b/modules/time_sheets/lib.js index a85f0d71..aec8c25a 100644 --- a/modules/time_sheets/lib.js +++ b/modules/time_sheets/lib.js @@ -16,7 +16,7 @@ along with iCE Hrm. If not, see . ------------------------------------------------------------------ -Original work Copyright (c) 2012 [Gamonoid Media Pvt. Ltd] +Original work Copyright (c) 2012 [Gamonoid Media Pvt. Ltd] Developer: Thilina Hasantha (thilina.hasantha[at]gmail.com / facebook.com/thilinah) */ @@ -79,9 +79,9 @@ EmployeeTimeSheetAdapter.method('renderForm', function(object) { $('.timesheet_start').html(Date.parse(object.date_start).toString('MMM d, yyyy (dddd)')); $('.timesheet_end').html(Date.parse(object.date_end).toString('MMM d, yyyy (dddd)')); - + this.currentTimesheet = object; - + this.getTimeEntries(); var st = Date.parse(object.date_start); @@ -127,9 +127,9 @@ EmployeeTimeSheetAdapter.method('renderForm', function(object) { }); $('#EmployeeTimesheetBlock').fullCalendar('gotoDate', st); - + $('.fc-toolbar').hide(); - + }); @@ -219,7 +219,7 @@ EmployeeTimeSheetAdapter.method('openTimeEntryDialog', function(object) { obj.currentTimesheet = this.currentTimesheet; obj.renderForm(object); obj.timesheetId = this.currentId; - + }); EmployeeTimeSheetAdapter.method('closeTimeEntryDialog', function() { @@ -231,14 +231,14 @@ EmployeeTimeSheetAdapter.method('getTimeEntries', function() { timesheetId = this.currentId; var sourceMappingJson = JSON.stringify(modJsList['tabEmployeeTimeEntry'].getSourceMapping()); object = {"id":timesheetId,"sm":sourceMappingJson}; - + var reqJson = JSON.stringify(object); - + var callBackData = []; callBackData['callBackData'] = []; callBackData['callBackSuccess'] = 'getTimeEntriesSuccessCallBack'; callBackData['callBackFail'] = 'getTimeEntriesFailCallBack'; - + this.customAction('getTimeEntries','modules=time_sheets',reqJson,callBackData); }); @@ -246,18 +246,18 @@ EmployeeTimeSheetAdapter.method('getTimeEntriesSuccessCallBack', function(callBa var entries = callBackData; var html = ""; var temp = '_start__end__duration__project__details_'; - + for(var i=0;i'; } - + html = html.replace(/_id_/g,id); html = html.replace(/_BASE_/g,this.baseUrl); html = html.replace(/_sdate_/g,data[1]); @@ -534,7 +534,7 @@ SubEmployeeTimeSheetAdapter.method('getActionButtonsHtml', function(id,data) { SubEmployeeTimeSheetAdapter.method('getCustomTableParams', function() { var that = this; var dataTableParams = { - "aoColumnDefs": [ + "aoColumnDefs": [ { "fnRender": function(data, cell){ return that.preProcessRemoteTableData(data, cell, 2) @@ -615,7 +615,7 @@ EmployeeTimeEntryAdapter.method('getFormFields', function() { EmployeeTimeEntryAdapter.method('getDates', function(startDate, stopDate) { - + var dateArray = new Array(); var currentDate = startDate; while (currentDate <= stopDate) { @@ -631,7 +631,7 @@ EmployeeTimeEntryAdapter.method('renderForm', function(object) { formHtml = formHtml.replace(/modJs/g,"modJsList['tabEmployeeTimeEntry']"); var html = ""; var fields = this.getFormFields(); - + for(var i=0;i'+k.toUTCString().slice(0, -13)+''; optionList += ''; } - - - + + + formHtml = formHtml.replace(/_id_/g,this.getTableName()+"_submit"); formHtml = formHtml.replace(/_fields_/g,html); $("#"+this.getTableName()+'Form').html(formHtml); $("#"+this.getTableName()+'Form').show(); $("#"+this.getTableName()).hide(); - + $("#"+this.getTableName()+'Form .datefield').datepicker({'viewMode':2}); $("#"+this.getTableName()+'Form .datetimefield').datetimepicker({ language: 'en' @@ -678,9 +678,9 @@ EmployeeTimeEntryAdapter.method('renderForm', function(object) { language: 'en', pickDate: false }); - + $("#"+this.getTableName()+'Form .select2Field').select2(); - + $("#date_select").html(optionList); @@ -726,20 +726,20 @@ EmployeeTimeEntryAdapter.method('setEmployeeProjects', function(employeeProjects EmployeeTimeEntryAdapter.method('save', function() { var validator = new FormValidation(this.getTableName()+"_submit",true,{'ShowPopup':false,"LabelErrorClass":"error"}); - + if(validator.checkValues()){ var params = validator.getFormParameters(); $(params).attr('timesheet',this.timesheetId); - + params.time_start = params.date_start; params.time_end = params.date_end; - + params.date_start = params.date_select+" "+params.date_start; params.date_end = params.date_select+" "+params.date_end; - - + + var msg = this.doCustomValidation(params); - + if(msg == null){ var id = $('#'+this.getTableName()+"_submit #id").val(); if(id != null && id != undefined && id != ""){ @@ -751,7 +751,7 @@ EmployeeTimeEntryAdapter.method('save', function() { $("#"+this.getTableName()+'Form .label').html(msg); $("#"+this.getTableName()+'Form .label').show(); } - + } }); @@ -764,7 +764,7 @@ EmployeeTimeEntryAdapter.method('doCustomValidation', function(params) { /* var sd = Date.parse(this.currentTimesheet.date_start); var ed = Date.parse(this.currentTimesheet.date_end).addDays(1); - + if(sd.compareTo(et) != -1 || sd.compareTo(st) > 0 || st.compareTo(ed) != -1 || et.compareTo(ed) != -1){ return "Start time and end time shoud be with in " + sd.toString('MMM d, yyyy (dddd)') + " and " + ed.toString('MMM d, yyyy (dddd)'); } @@ -779,7 +779,7 @@ EmployeeTimeEntryAdapter.method('addSuccessCallBack', function(callBackData,serv EmployeeTimeEntryAdapter.method('deleteRow', function(id) { this.deleteObj(id,[]); - + }); EmployeeTimeEntryAdapter.method('deleteSuccessCallBack', function(callBackData,serverData) { @@ -807,10 +807,10 @@ QtsheetAdapter.method('validateCellValue', function(element, evt, newValue) { return false; } var val = parseFloat(newValue); - if(val <= 0 || val > 24){ + if(val < 0 || val > 24){ return false; } - + //Update total //Find current column number //Adding 2 because nth child is based on 1 and we are adding a virtual column for row names @@ -845,7 +845,7 @@ QtsheetAdapter.method('validateCellValue', function(element, evt, newValue) { if(columnTotal > 24){ return false; } - + modJs.addCellDataUpdate(element.data('colId'),element.data('rowId'),newValue); return true; }); From 088817172f986a77593cc84aa48a067c19b6deb1 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 8 Oct 2017 19:31:27 +0200 Subject: [PATCH 06/21] =?UTF-8?q?Import=20-=20Export=20=E2=9A=99=EF=B8=8F?= =?UTF-8?q?=20implementation=20for=20payroll?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fileupload_page.php | 12 +- images/file-icons/json.png | Bin 0 -> 559 bytes migrations/list.php | 2 + ...003_200301_add_deduction_group_payroll.php | 23 ++ .../v20171003_200302_payroll_meta_export.php | 41 +++ src/Data/Admin/Api/AbstractDataImporter.php | 41 ++- src/Data/Admin/Api/DataActionManager.php | 31 +- src/Data/Admin/Api/DataImporter.php | 15 + src/Data/Admin/Import/PayrollDataImporter.php | 318 ++++++++++++++++++ src/Model/Report.php | 16 + .../Admin/Reports/PayrollDataExport.php | 155 +++++++++ 11 files changed, 619 insertions(+), 35 deletions(-) create mode 100644 images/file-icons/json.png create mode 100644 migrations/v20171003_200301_add_deduction_group_payroll.php create mode 100644 migrations/v20171003_200302_payroll_meta_export.php create mode 100644 src/Data/Admin/Api/DataImporter.php create mode 100644 src/Data/Admin/Import/PayrollDataImporter.php create mode 100644 src/Reports/Admin/Reports/PayrollDataExport.php diff --git a/fileupload_page.php b/fileupload_page.php index afc1d7d8..ad03cd8e 100644 --- a/fileupload_page.php +++ b/fileupload_page.php @@ -40,20 +40,20 @@ function checkFileType (elementName, fileTypes) { if (fileElement.value.lastIndexOf(".") > 0) { fileExtension = fileElement.value.substring(fileElement.value.lastIndexOf(".") + 1, fileElement.value.length); } - + fileExtension = fileExtension.toLowerCase(); - + var allowed = fileTypes.split(","); - + if (allowed.indexOf(fileExtension) < 0) { fileElement.value = ""; alert('Selected file type is not supported'); clearFileElement(elementName); return false; } - + return true; - + } function clearFileElement (elementName) { @@ -76,4 +76,4 @@ function clearFileElement (elementName) { - \ No newline at end of file + diff --git a/images/file-icons/json.png b/images/file-icons/json.png new file mode 100644 index 0000000000000000000000000000000000000000..d4aaa51b940757336cecfc035a169925e5da7661 GIT binary patch literal 559 zcmV+~0?_@5P)QGEnMgRZ*=jYq!=jZI~-@vWF!?eS`tij&i)ZyOL;@{Qj>EPw% z+vDQc+StsOcc__qs+xPMntQ98e5;&&tetPliL|Ygy04bJ zua~^BnZ2@_zOtRVw4A`Soxr!FzPO^pxu(Clr@y+S#k#1#yQ;yws=>ah$iAw{z^ux^ zvBbfy%fqqF#k9}HxX8)4(#g5f%e&Ogz17Xa&CkKt&&AHt$FMB>I0Z`p000hj zQchC<6%{BoL`r03X!7;;{ukVK761SMok>JNR2WxX%heKsPymGCRTTT!-GSZR-LUWf zI$nUt_}}d}vw+P@J)Z{v0Lj>V1l)hH54gUtP|4%&a`D>@Q23@+Cn@Q0>~ni#^=U$T zMU_<6CTJ~=&usoKEU9executeQuery($sql); + } + + public function down(){ + $sql = <<<'SQL' + alter table PayrollColumns drop column `deduction_group`; +SQL; + + return $this->executeQuery($sql); + } + +} + diff --git a/migrations/v20171003_200302_payroll_meta_export.php b/migrations/v20171003_200302_payroll_meta_export.php new file mode 100644 index 00000000..1229d405 --- /dev/null +++ b/migrations/v20171003_200302_payroll_meta_export.php @@ -0,0 +1,41 @@ +executeQuery($sql); + + + $sql = <<<'SQL' + INSERT INTO `DataImport` (`name`, `dataType`, `details`, `columns`, `updated`, `created`) VALUES + ('Payroll Data Import', 'PayrollDataImporter', '', '[]', '2016-08-14 02:51:56', '2016-08-14 02:51:56'); + +SQL; + return $this->executeQuery($sql); + } + + public function down(){ + $sql = <<<'SQL' + delete from Reports where name = 'Payroll Meta Data Export'; +SQL; + + $this->executeQuery($sql); + + $sql = <<<'SQL' + delete from DataImport where name = 'Attendance Data Import'; +SQL; + + return $this->executeQuery($sql); + } + +} + diff --git a/src/Data/Admin/Api/AbstractDataImporter.php b/src/Data/Admin/Api/AbstractDataImporter.php index 40e6485b..56217433 100644 --- a/src/Data/Admin/Api/AbstractDataImporter.php +++ b/src/Data/Admin/Api/AbstractDataImporter.php @@ -7,7 +7,7 @@ use Data\Common\Model\DataImport; use FieldNames\Common\Model\CustomField; use Utils\LogManager; -abstract class AbstractDataImporter +abstract class AbstractDataImporter implements DataImporter { protected $dataImport = null; @@ -22,7 +22,7 @@ abstract class AbstractDataImporter protected $columnsCompeted = array(); protected $relatedColumns = array(); - public function getRowObjects() + public function getResult() { return $this->rowObjects; } @@ -243,4 +243,41 @@ abstract class AbstractDataImporter return false; } abstract public function fixBeforeSave($object, $data); + + + public function process($data, $dataImportId) + { + $data = str_replace("\r", "\n", $data); + $data = str_replace("\n\n", "\n", $data); + + $lines = str_getcsv($data, "\n"); + + $headerProcessed = false; + + $counter = 0; + + LogManager::getInstance()->info("Line Count:".count($lines)); + + $res = array(); + + foreach ($lines as $line) { + $cells = str_getcsv($line, ","); + if ($headerProcessed === false) { + $this->setDataImportId($dataImportId); + $this->processHeader($cells); + $headerProcessed = true; + } else { + $result = $this->processDataRow($counter, $cells); + $res[] = array($cells,$result); + } + $counter++; + } + + return $res; + } + + public function getLastStatus() + { + return IceResponse::SUCCESS; + } } diff --git a/src/Data/Admin/Api/DataActionManager.php b/src/Data/Admin/Api/DataActionManager.php index 9df47d3f..64510317 100644 --- a/src/Data/Admin/Api/DataActionManager.php +++ b/src/Data/Admin/Api/DataActionManager.php @@ -36,15 +36,6 @@ class DataActionManager extends SubActionManager $data = file_get_contents($url); - $data = str_replace("\r", "\n", $data); - $data = str_replace("\n\n", "\n", $data); - - $lines = str_getcsv($data, "\n"); - - $headerProcessed = false; - - $counter = 0; - $dataImport = new DataImport(); $dataImport->Load("id =?", array($dataFile->data_import_definition)); if (empty($dataImport->id)) { @@ -54,27 +45,13 @@ class DataActionManager extends SubActionManager $processClass = '\\Data\Admin\Import\\'.$dataImport->dataType; $processObj = new $processClass(); - LogManager::getInstance()->info("Line Count:".count($lines)); - - $res = array(); - - foreach ($lines as $line) { - $cells = str_getcsv($line, ","); - if ($headerProcessed === false) { - $processObj->setDataImportId($dataImport->id); - $processObj->processHeader($cells); - $headerProcessed = true; - } else { - $result = $processObj->processDataRow($counter, $cells); - $res[] = array($cells,$result); - } - $counter++; + $res = $processObj->process($data, $dataImport->id); + if ($processObj->getLastStatus() === IceResponse::SUCCESS) { + $dataFile->status = "Processed"; } - - $dataFile->status = "Processed"; $dataFile->details = json_encode($res, JSON_PRETTY_PRINT); $dataFile->Save(); - return new IceResponse(IceResponse::SUCCESS, $processObj->getRowObjects()); + return new IceResponse($processObj->getLastStatus(), $processObj->getResult()); } private function processHeader($dataImportId, $data) diff --git a/src/Data/Admin/Api/DataImporter.php b/src/Data/Admin/Api/DataImporter.php new file mode 100644 index 00000000..5bc7378c --- /dev/null +++ b/src/Data/Admin/Api/DataImporter.php @@ -0,0 +1,15 @@ +model; + } + + public function process($data, $dataImporterId) + { + $compStructure = new CompanyStructure(); + $compStructure->Load("1 = 1 limit 1", array()); + if (empty($compStructure->id)) { + $this->lastStatus = IceResponse::ERROR; + return "No company structures exists"; + } + $this->model = json_decode($data); + $deductionGroup = $this->createDeductionGroup($this->model); + if (!$deductionGroup) { + $this->lastStatus = IceResponse::ERROR; + return "Deduction group already exists"; + } + $salaryComponentTypeIdMap = $this->addSalaryComponentTypes($this->model); + $salaryComponentIdMap = $this->addSalaryComponents($this->model, $salaryComponentTypeIdMap); + $payrollColumnIdMap = $this->addPayrollColumns($this->model, $deductionGroup->id, $salaryComponentIdMap); + $deductionIdMap = $this->addDeductions( + $this->model, + $deductionGroup->id, + $salaryComponentTypeIdMap, + $salaryComponentIdMap, + $payrollColumnIdMap + ); + $this->refinePayrollColumns($payrollColumnIdMap, $deductionIdMap); + $payslipTemplate = $this->addPayslipTemplate($this->model, $payrollColumnIdMap); + $this->addPayroll( + $this->model, + $payrollColumnIdMap, + $deductionGroup->id, + $payslipTemplate->id, + $compStructure->id + ); + $this->lastStatus = IceResponse::SUCCESS; + + return $this->model; + } + + protected function addPayroll($model, $payrollColumnIdMap, $deductionGroupId, $payslipId, $departmentId) + { + $samplePr = $model->samplePayroll; + $payroll = new Payroll(); + $payroll->name = $samplePr->name; + $payroll->pay_period = $samplePr->pay_period; + $payroll->date_start = $samplePr->date_start; + $payroll->date_end = $samplePr->date_end; + $payroll->columns = $this->replaceJsonIds( + $samplePr->columns, + $payrollColumnIdMap + ); + $payroll->status = $samplePr->status; + $payroll->deduction_group = $deductionGroupId; + $payroll->payslipTemplate = $payslipId; + $payroll->department = $departmentId; + $ok = $payroll->Save(); + + if (!$ok) { + LogManager::getInstance()->error($payroll->ErrorMsg()); + } + } + + protected function addPayslipTemplate($model, $payrollColumnIdMap) + { + $pst = $model->payslipTemplate; + $payslipTemplate = new PayslipTemplate(); + $payslipTemplate->name = $pst->name; + + $data = json_decode($pst->data, true); + $newData = []; + foreach ($data as $row) { + if ($row['type'] === 'Payroll Column') { + $row['payrollColumn'] = $payrollColumnIdMap[$row['payrollColumn']]; + } + $newData[] = $row; + } + + $payslipTemplate->data = json_encode($newData); + + $payslipTemplate->status = $pst->status; + $payslipTemplate->created = $pst->created; + $payslipTemplate->updated = $pst->updated; + + $payslipTemplate->Save(); + + return $payslipTemplate; + } + + protected function refinePayrollColumns($payrollColumnIdMap, $deductionIdMap) + { + $payrollColumn = new PayrollColumn(); + $columns = $payrollColumn->Find('id in ('.implode(',', array_values($payrollColumnIdMap)).')', array()); + foreach ($columns as $column) { + $column->deductions = $this->replaceJsonIds( + $column->deductions, + $deductionIdMap + ); + + $column->add_columns = $this->replaceJsonIds( + $column->add_columns, + $payrollColumnIdMap + ); + + $column->sub_columns = $this->replaceJsonIds( + $column->sub_columns, + $payrollColumnIdMap + ); + + $column->sub_columns = $this->replaceJsonIdsForCalculations( + $column->calculation_columns, + $payrollColumnIdMap + ); + + $column->Save(); + } + } + + protected function addPayrollColumns($model, $deductionGroupId, $salaryComponentIdMap) + { + $payrollColumnIdMap = []; + $payrollColumns = $model->columns; + foreach ($payrollColumns as $payrollColumn) { + $column = new PayrollColumn(); + $column->name = $payrollColumn->name; + $column->calculation_hook = $payrollColumn->calculation_hook; + $column->salary_components = $this->replaceJsonIds( + $payrollColumn->salary_components, + $salaryComponentIdMap + ); + + $column->deductions = $payrollColumn->deductions; // need to map + $column->add_columns = $payrollColumn->add_columns; // need to map + $column->sub_columns = $payrollColumn->sub_columns; // need to map + $column->colorder = $payrollColumn->colorder; + $column->editable = $payrollColumn->editable; + $column->enabled = $payrollColumn->enabled; + $column->default_value = $payrollColumn->default_value; + $column->calculation_columns = $payrollColumn->calculation_columns; // need to map + $column->calculation_function = $payrollColumn->calculation_function; + $column->deduction_group = $deductionGroupId; + + $column->Save(); + + $payrollColumnIdMap[$payrollColumn->id] = $column->id; + } + return $payrollColumnIdMap; + } + + protected function addDeductions( + $model, + $deductionGroupId, + $salaryComponentTypeIdMap, + $salaryComponentIdMap, + $payrollColumnIdMap + ) { + $deductionIdMap = []; + $deductions = $model->deductions; + + foreach ($deductions as $deduction) { + $dbDeduction = new Deduction(); + $dbDeduction->name = $deduction->name; + $dbDeduction->componentType = $this->replaceJsonIds( + $deduction->componentType, + $salaryComponentTypeIdMap + ); + $dbDeduction->component = $this->replaceJsonIds( + $deduction->component, + $salaryComponentIdMap + ); + + $dbDeduction->payrollColumn = $payrollColumnIdMap[$deduction->payrollColumn]; + $dbDeduction->rangeAmounts = $deduction->rangeAmounts; + $dbDeduction->deduction_group = $deductionGroupId; + + $dbDeduction->Save(); + $deductionIdMap[$deduction->id] = $dbDeduction->id; + } + return $deductionIdMap; + } + + protected function createDeductionGroup($model) + { + $deductionGroup = new DeductionGroup(); + $deductionGroup->Load("name = ?", array($model->name)); + if (!empty($deductionGroup->id)) { + return false; + } + + $deductionGroup->name = $model->name; + $deductionGroup->description = $model->description; + $ok = $deductionGroup->Save(); + + if (!$ok) { + return false; + } + + return $deductionGroup; + } + + /** + * @param $salaryComponentTypeIdMap + */ + protected function addSalaryComponentTypes($model) + { + $salaryComponentTypeIdMap = []; + $salaryComponentTypes = $model->salaryComponentTypes; + foreach ($salaryComponentTypes as $salaryComponentType) { + $tempSct = new SalaryComponentType(); + $tempSct->Load( + "code = ? and name = ?", + array($salaryComponentType->code, $salaryComponentType->name) + ); + + if (!empty($tempSct->id)) { + $salaryComponentTypeIdMap[$salaryComponentType->id] = $tempSct->id; + continue; + } + + $tempSct = new SalaryComponentType(); + $tempSct->code = $salaryComponentType->code; + $tempSct->name = $salaryComponentType->name; + $tempSct->Save(); + + $salaryComponentTypeIdMap[$salaryComponentType->id] = $tempSct->id; + } + + return $salaryComponentTypeIdMap; + } + + protected function addSalaryComponents($model, $salaryComponentTypeIdMap) + { + $salaryComponentIdMap = []; + $salaryComponents = $model->salaryComponents; + foreach ($salaryComponents as $salaryComponent) { + $tempSct = new SalaryComponent(); + $tempSct->Load( + "componentType = ? and name = ?", + array( + $salaryComponentTypeIdMap[$salaryComponent->componentType], + $salaryComponent->name + ) + ); + + if (!empty($tempSct->id)) { + $salaryComponentIdMap[$salaryComponent->id] = $tempSct->id; + continue; + } + + $tempSct = new SalaryComponent(); + $tempSct->name = $salaryComponent->name; + $tempSct->componentType = $salaryComponentTypeIdMap[$salaryComponent->componentType]; + $tempSct->details = $salaryComponent->details; + $tempSct->Save(); + + $salaryComponentIdMap[$salaryComponent->id] = $tempSct->id; + } + + return $salaryComponentIdMap; + } + + private function replaceJsonIds($ids, $idMap) + { + $newIds = []; + $data = json_decode($ids, true); + foreach ($data as $id) { + $newIds[] = $idMap[$id]; + } + return json_encode($newIds); + } + + private function replaceJsonIdsForCalculations($calculations, $idMap) + { + $newCalculations = []; + $data = json_decode($calculations, true); + foreach ($data as $cal) { + $cal['column'] = $idMap[$cal['column']]; + $newCalculations[] = $cal; + } + return json_encode($newCalculations); + } + + public function getLastStatus() + { + return $this->lastStatus; + } +} diff --git a/src/Model/Report.php b/src/Model/Report.php index 47d87598..b51bbecd 100644 --- a/src/Model/Report.php +++ b/src/Model/Report.php @@ -31,5 +31,21 @@ class Report extends BaseModel return $entry; } + public function getCustomFilterQuery($filter) + { + $filter = json_decode($filter, true); + if ($filter['type'] === 'Reports') { + $query = ' and report_group <> ?'; + } elseif ($filter['type'] === 'Exports') { + $query = ' and report_group = ?'; + } else { + $query = ''; + } + + $queryData = array('Payroll'); + + return array($query, $queryData); + } + public $table = 'Reports'; } diff --git a/src/Reports/Admin/Reports/PayrollDataExport.php b/src/Reports/Admin/Reports/PayrollDataExport.php new file mode 100644 index 00000000..449e9ea2 --- /dev/null +++ b/src/Reports/Admin/Reports/PayrollDataExport.php @@ -0,0 +1,155 @@ +Load("id = ?", array($request['deduction_group'])); + if (empty($deductionGroup->id)) { + return ['Calculation Group not found']; + } else { + $data = [ + 'name' => $deductionGroup->name, + 'description' => $deductionGroup->description, + ]; + } + } + + // Add Deductions + $deduction = new Deduction(); + $deductions = $deduction->Find("deduction_group = ?", array($deductionGroup->id)); + $data['deductions'] = []; + foreach ($deductions as $deduction) { + $data['deductions'][] = [ + 'id' => $deduction->id, + 'name' => $deduction->name, + 'componentType' => $deduction->componentType, + 'component' => $deduction->component, + 'payrollColumn' => $deduction->payrollColumn, + 'rangeAmounts' => $deduction->rangeAmounts, + ]; + } + + // Payroll Columns + $col = new PayrollColumn(); + $columns = $col->Find("deduction_group = ?", array($deductionGroup->id)); + $data['columns'] = []; + $salaryComponentIds = []; + foreach ($columns as $col) { + $data['columns'][] = [ + 'id' => $col->id, + 'name' => $col->name, + 'calculation_hook' => $col->calculation_hook, + 'salary_components' => $col->salary_components, // ["1"] + 'deductions' => $col->deductions, // ["1"] + 'add_columns' => $col->add_columns, // ["1"] + 'sub_columns' => $col->sub_columns, + 'colorder' => $col->colorder, + 'editable' => $col->editable, + 'enabled' => $col->enabled, + 'default_value' => $col->default_value, + 'calculation_columns' => $col->calculation_columns, //[{"name":"O","column":"107","id":"calculation_columns_1"}] + 'calculation_function' => $col->calculation_function, + ]; + + if (!empty($col->salary_components)) { + $ids = json_decode($col->salary_components, true); + foreach ($ids as $id) { + $salaryComponentIds[$id] = $id; + } + } + } + + // Get Salary Components + $data['salaryComponents'] = []; + $salaryComponentGroupIds = []; + $salaryComponent = new SalaryComponent(); + $salaryComponents = $salaryComponent->Find( + "id in (" . implode(',', array_keys($salaryComponentIds)) .")", + array() + ); + foreach ($salaryComponents as $salaryComponent) { + $data['salaryComponents'][] = [ + 'id' => $salaryComponent->id, + 'name' => $salaryComponent->name, + 'componentType' => $salaryComponent->componentType, + 'details' => $salaryComponent->details, + ]; + + $salaryComponentGroupIds[$salaryComponent->componentType] = $salaryComponent->componentType; + } + + // Get Salary Component Types + $data['salaryComponentTypes'] = []; + $salaryComponentType = new SalaryComponentType(); + $salaryComponentTypes = $salaryComponentType->Find( + "id in (" . implode(',', array_keys($salaryComponentGroupIds)) .")", + array() + ); + foreach ($salaryComponentTypes as $salaryComponentType) { + $data['salaryComponentTypes'][] = [ + 'id' => $salaryComponentType->id, + 'code' => $salaryComponentType->code, + 'name' => $salaryComponentType->name, + ]; + } + + // Get Sample Payroll + $payroll = new Payroll(); + $payroll->Load("id = ?", array($request['payroll'])); + + $data['samplePayroll'] = [ + 'name' => $payroll->name, + 'pay_period' => $payroll->pay_period, + 'columns' => $payroll->columns, + 'date_start' => $payroll->date_start, + 'date_end' => $payroll->date_end, + 'status' => $payroll->status, + ]; + + $payslipTemplate = new PayslipTemplate(); + $payslipTemplate->Load("id = ?", array($payroll->payslipTemplate)); + + $data['payslipTemplate'] = [ + 'name' => $payslipTemplate->name, + 'data' => $payslipTemplate->data, + 'status' => $payslipTemplate->status, + 'created' => $payslipTemplate->created, + 'updated' => $payslipTemplate->updated, + ]; + + return $data; + } + + public function createReportFile($report, $data) + { + $fileFirstPart = "Report_".str_replace(" ", "_", $report->name)."-".date("Y-m-d_H-i-s"); + $fileName = $fileFirstPart.".txt"; + + $fileFullName = CLIENT_BASE_PATH.'data/'.$fileName; + $fp = fopen($fileFullName, 'w'); + + fwrite($fp, json_encode($data, JSON_PRETTY_PRINT)); + + fclose($fp); + return array($fileFirstPart, $fileName, $fileFullName); + } +} From 92f7e11dd1d7f806ab100ff7ba53f1254283aaf3 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Mon, 9 Oct 2017 07:53:51 +0200 Subject: [PATCH 07/21] Remove payroll data from master data --- scripts/icehrm_master_data.sql | 75 ---------------------------------- 1 file changed, 75 deletions(-) diff --git a/scripts/icehrm_master_data.sql b/scripts/icehrm_master_data.sql index de61c4d3..132d2430 100644 --- a/scripts/icehrm_master_data.sql +++ b/scripts/icehrm_master_data.sql @@ -1504,78 +1504,3 @@ REPLACE INTO `UserReports` (`name`, `details`, `parameters`, `query`, `paramOrde ('Download Payslips', 'Download your payslips', '[\r\n[ "payroll", {"label":"Select Payroll","type":"select","allow-null":false,"remote-source":["Payroll","id","name","getEmployeePayrolls"]}]]', 'PayslipReport', '["payroll"]', 'Class','Finance','PDF'); - - - - - -INSERT INTO `DeductionGroup` VALUES - (1,'Sri Lanka Payroll Calculation',''); - - -INSERT INTO `PayslipTemplates` (`id`, `name`, `data`, `status`, `created`, `updated`) VALUES - (1, 'Sri Lanka - Default Payslip', '[{"type":"Company Logo","payrollColumn":"NULL","label":"","text":"","fontSize":"Normal","fontStyle":"Normal","fontColor":"#000000","status":"Show","id":"data_1"},{"type":"Company Name","payrollColumn":"NULL","label":"","text":"","fontSize":"Normal","fontStyle":"Normal","fontColor":"","status":"Show","id":"data_2"},{"type":"Separators","payrollColumn":"NULL","label":"","text":"","fontSize":"Normal","fontStyle":"Normal","fontColor":"","status":"Show","id":"data_8"},{"type":"Payroll Column","payrollColumn":"5","label":"Basic Salary","text":"","status":"Show","id":"data_3"},{"type":"Payroll Column","payrollColumn":"6","label":"Fixed Allowance","text":"","status":"Show","id":"data_4"},{"type":"Payroll Column","payrollColumn":"7","label":"Gross Pay","text":"","status":"Show","id":"data_11"},{"type":"Separators","payrollColumn":"NULL","label":"","text":"","fontSize":"Normal","fontStyle":"Normal","fontColor":"","status":"Show","id":"data_9"},{"type":"Text","payrollColumn":"NULL","label":"","text":"Deductions","status":"Show","id":"data_13"},{"type":"Payroll Column","payrollColumn":"8","label":"EPF Employee Contribution","text":"","status":"Show","id":"data_6"},{"type":"Payroll Column","payrollColumn":"13","label":"PAYE Tax","text":"","status":"Show","id":"data_14"},{"type":"Payroll Column","payrollColumn":"14","label":"Stamp Duty","text":"","status":"Show","id":"data_15"},{"type":"Payroll Column","payrollColumn":"15","label":"Total Deductions","text":"","status":"Show","id":"data_16"},{"type":"Separators","payrollColumn":"NULL","label":"","text":"","status":"Show","id":"data_17"},{"type":"Text","payrollColumn":"NULL","label":"","text":"Employer Contributions","status":"Show","id":"data_18"},{"type":"Payroll Column","payrollColumn":"9","label":"EPF Employer Contribution","text":"","status":"Show","id":"data_19"},{"type":"Payroll Column","payrollColumn":"7","label":"ETF Employer Contribution","text":"","status":"Show","id":"data_20"},{"type":"Separators","payrollColumn":"7","label":"","text":"","status":"Show","id":"data_21"},{"type":"Text","payrollColumn":"7","label":"","text":"Totals","status":"Show","id":"data_22"},{"type":"Payroll Column","payrollColumn":"11","label":"Total EPF 20%","text":"","status":"Show","id":"data_23"},{"type":"Payroll Column","payrollColumn":"12","label":"Total for PAYE","text":"","status":"Show","id":"data_24"},{"type":"Payroll Column","payrollColumn":"16","label":"Net Salary","text":"","status":"Show","id":"data_25"}]', NULL, '2016-06-29 22:07:12', '2016-06-29 22:07:12'); - -INSERT INTO `Payroll` VALUES - (1,'Sri Lanka Payroll Sample',4,1,NULL,'[\"5\",\"8\",\"9\",\"10\",\"6\",\"7\",\"11\",\"12\",\"13\",\"14\",\"15\",\"16\"]','2016-03-01','2016-03-31','Draft', 1); - -INSERT INTO `PayrollColumns` VALUES - (5,'LK - Basic Salary',NULL,'[\"1\"]','[]','[]','[]',5,'No','Yes','0.00',NULL,NULL), - (6,'LK - Fixed Allowance',NULL,'[\"2\"]','[]','[]','[]',6,'No','Yes','0.00',NULL,NULL), - (7,'LK - Gross Pay',NULL,'[]','[]','[\"5\",\"6\"]','[]',7,'No','Yes','0.00',NULL,NULL), - (8,'LK - EPF Employee Contribution',NULL,'[]','[\"1\"]','[]','[]',8,'No','Yes','0.00',NULL,NULL), - (9,'LK - EPF Employer Contribution',NULL,'[]','[\"2\"]','[]','[]',9,'No','Yes','0.00',NULL,NULL), - (10,'LK - ETF Employer Contribution',NULL,'[]','[\"3\"]','[]','[]',10,'No','Yes','0.00',NULL,NULL), - (11,'LK - Total EPF 20%',NULL,'[]','[]','[\"8\",\"9\"]','[]',11,'No','Yes','0.00',NULL,NULL), - (12,'LK - Total for PAYE',NULL,'[]','[]','[\"7\"]','[]',12,'No','Yes','0.00',NULL,NULL), - (13,'LK - PAYE Tax',NULL,'[]','[\"4\"]','[]','[]',13,'No','Yes','0.00',NULL,NULL), - (14,'LK - Stamp Duty',NULL,'[]','[\"5\"]','[]','[]',14,'No','Yes','0.00',NULL,NULL), - (15,'LK - Total Deductions',NULL,'[]','[]','[\"8\",\"13\",\"14\"]','[]',15,'No','Yes','0.00',NULL,NULL), - (16,'LK - Salary to Bank',NULL,'[]','[]','[\"7\"]','[\"15\"]',16,'No','Yes','0.00',NULL,NULL); - -INSERT INTO `Deductions` VALUES - (1,'EPF Employee Contribution','[]','[]',7,'[{\"lowerCondition\":\"No Lower Limit\",\"lowerLimit\":\"0\",\"upperCondition\":\"No Upper Limit\",\"upperLimit\":\"0\",\"amount\":\"X*0.08\",\"id\":\"rangeAmounts_1\"}]',1), - (2,'EPF Employer Contribution','[]','[]',7,'[{\"lowerCondition\":\"No Lower Limit\",\"lowerLimit\":\"0\",\"upperCondition\":\"No Upper Limit\",\"upperLimit\":\"0\",\"amount\":\"X*0.12\",\"id\":\"rangeAmounts_1\"}]',1), - (3,'ETF Employer Contribution','[]','[]',7,'[{\"lowerCondition\":\"No Lower Limit\",\"lowerLimit\":\"0\",\"upperCondition\":\"No Upper Limit\",\"upperLimit\":\"0\",\"amount\":\"X*0.03\",\"id\":\"rangeAmounts_1\"}]',1), - (4,'PAYE Tax','[]','[]',12,'[{\"lowerCondition\":\"No Lower Limit\",\"lowerLimit\":\"0\",\"upperCondition\":\"lte\",\"upperLimit\":\"62500\",\"amount\":\"0\",\"id\":\"rangeAmounts_1\"},{\"lowerCondition\":\"gt\",\"lowerLimit\":\"62500\",\"upperCondition\":\"lte\",\"upperLimit\":\"104167\",\"amount\":\"X*0.04 - 2500\",\"id\":\"rangeAmounts_2\"},{\"lowerCondition\":\"gt\",\"lowerLimit\":\"104167\",\"upperCondition\":\"lte\",\"upperLimit\":\"145833\",\"amount\":\"X*0.08 - 6667\",\"id\":\"rangeAmounts_3\"},{\"lowerCondition\":\"gt\",\"lowerLimit\":\"145833\",\"upperCondition\":\"lte\",\"upperLimit\":\"187500\",\"amount\":\"X*0.12-12500\",\"id\":\"rangeAmounts_4\"},{\"lowerCondition\":\"gt\",\"lowerLimit\":\"187500\",\"upperCondition\":\"No Upper Limit\",\"upperLimit\":\"0\",\"amount\":\"X*0.16 - 20000\",\"id\":\"rangeAmounts_5\"}]',1), - (5,'Stamp Duty','[]','[]',12,'[{\"lowerCondition\":\"No Lower Limit\",\"lowerLimit\":\"0\",\"upperCondition\":\"lte\",\"upperLimit\":\"25000\",\"amount\":\"0\",\"id\":\"rangeAmounts_1\"},{\"lowerCondition\":\"gt\",\"lowerLimit\":\"25000\",\"upperCondition\":\"No Upper Limit\",\"upperLimit\":\"0\",\"amount\":\"25\",\"id\":\"rangeAmounts_2\"}]',1); - - -INSERT INTO `DeductionGroup` VALUES - (2,'Ghana Payroll Calculation',''); - -INSERT INTO `PayslipTemplates` VALUES - (2,'Ghana Default','[{\"type\":\"Company Name\",\"payrollColumn\":\"NULL\",\"label\":\"\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_1\"},{\"type\":\"Separators\",\"payrollColumn\":\"NULL\",\"label\":\"\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_3\"},{\"type\":\"Payroll Column\",\"payrollColumn\":\"105\",\"label\":\"\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_4\"},{\"type\":\"Payroll Column\",\"payrollColumn\":\"106\",\"label\":\"\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_5\"},{\"type\":\"Payroll Column\",\"payrollColumn\":\"107\",\"label\":\"\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_6\"},{\"type\":\"Payroll Column\",\"payrollColumn\":\"112\",\"label\":\"Total\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_7\"},{\"type\":\"Separators\",\"payrollColumn\":\"NULL\",\"label\":\"\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_8\"},{\"type\":\"Text\",\"payrollColumn\":\"NULL\",\"label\":\"\",\"text\":\"Deductions \",\"status\":\"Show\",\"id\":\"data_9\"},{\"type\":\"Payroll Column\",\"payrollColumn\":\"109\",\"label\":\"SSNIT (5.5%)\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_10\"},{\"type\":\"Payroll Column\",\"payrollColumn\":\"113\",\"label\":\"Tax (1st Level 5%)\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_11\"},{\"type\":\"Payroll Column\",\"payrollColumn\":\"114\",\"label\":\"Tax (2nd Level 10%)\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_12\"},{\"type\":\"Payroll Column\",\"payrollColumn\":\"115\",\"label\":\"Tax (3rd Level 17.5%)\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_13\"},{\"type\":\"Payroll Column\",\"payrollColumn\":\"120\",\"label\":\"Tax (4th Level 25%)\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_14\"},{\"type\":\"Payroll Column\",\"payrollColumn\":\"121\",\"label\":\"Overtime Allow. Tax (5%)\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_15\"},{\"type\":\"Payroll Column\",\"payrollColumn\":\"122\",\"label\":\"Total (PAYE Tax)\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_16\"},{\"type\":\"Separators\",\"payrollColumn\":\"NULL\",\"label\":\"\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_17\"},{\"type\":\"Payroll Column\",\"payrollColumn\":\"123\",\"label\":\"Sub Total\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_18\"},{\"type\":\"Separators\",\"payrollColumn\":\"NULL\",\"label\":\"\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_19\"},{\"type\":\"Payroll Column\",\"payrollColumn\":\"125\",\"label\":\"Netto Monthly Salary\",\"text\":\"\",\"status\":\"Show\",\"id\":\"data_20\"}]',NULL,'2016-08-30 21:53:13','2016-08-30 21:53:13'); - - -INSERT INTO `Payroll` VALUES - (6,'Ghana Payroll Sample',4,1,NULL,'[\"123\",\"125\",\"106\",\"124\",\"113\",\"114\",\"115\",\"121\",\"107\",\"120\",\"109\",\"105\",\"112\",\"108\",\"122\"]','2016-08-01','2016-08-31','Draft',2); - - -INSERT INTO `PayrollColumns` VALUES - (105,'GH - Salary (Basic)',NULL,'[\"1\"]','[]','[]','[]',1,'No','Yes','0.00','',''), - (106,'GH - Housing Allowance',NULL,'[]','[\"101\"]','[]','[]',2,'No','Yes','0.00','',''), - (107,'GH - Overtime Allowance',NULL,'[]','[\"102\"]','[]','[]',3,'No','Yes','0.00','',''), - (108,'GH - Total',NULL,'[]','[]','[\"106\",\"107\",\"105\"]','[]',4,'No','Yes','0.00','',''), - (109,'GH - SSNIT',NULL,'[]','[\"103\"]','[]','[]',5,'No','Yes','0.00','',''), - (112,'GH - Taxable Income',NULL,'[]','[]','[\"106\",\"105\"]','[\"109\"]',7,'No','Yes','0.00','',''), - (113,'GH - Next 108 GHC',NULL,'[]','[\"106\"]','[]','[]',9,'No','Yes','0.00','',''), - (114,'GH - Next 151 GHC',NULL,'[]','[\"107\"]','[]','[]',10,'No','Yes','0.00','',''), - (115,'GH - Next 2765 GHC',NULL,'[]','[\"108\"]','[]','[]',11,'No','Yes','0.00','',''), - (120,'GH - Remaining after 3240 GHC',NULL,'[]','[\"111\"]','[]','[]',12,'No','Yes','0.00','',''), - (121,'GH - Overtime Allow. Tax',NULL,'[]','[]','[]','[]',13,'No','Yes','0.00','[{\"name\":\"O\",\"column\":\"107\",\"id\":\"calculation_columns_1\"}]','O*0.05'), - (122,'GH - Total (PAYE Tax)',NULL,'[]','[]','[\"113\",\"114\",\"115\",\"120\",\"121\"]','[]',14,'No','Yes','0.00','',''), - (123,'GH - Deductions - Sub Total',NULL,'[]','[]','[\"109\",\"122\"]','[]',15,'No','Yes','0.00','',''), - (125,'GH - Final Total',NULL,'[]','[]','[\"108\"]','[\"123\"]',16,'No','Yes','0.00','',''); - - -INSERT INTO `Deductions` VALUES - (101,'Housing Allowance (10%)','[]','[\"1\"]',NULL,'[{\"lowerCondition\":\"No Lower Limit\",\"lowerLimit\":0,\"upperCondition\":\"No Upper Limit\",\"upperLimit\":0,\"amount\":\"X*0.1\",\"id\":\"rangeAmounts_1\"}]',2), - (102,'Overtime Allowance (10%)','[]','[\"1\"]',NULL,'[{\"lowerCondition\":\"No Lower Limit\",\"lowerLimit\":0,\"upperCondition\":\"No Upper Limit\",\"upperLimit\":0,\"amount\":\"X*0.1\",\"id\":\"rangeAmounts_1\"}]',2), - (103,'SSNIT','[]','[\"1\"]',NULL,'[{\"lowerCondition\":\"No Lower Limit\",\"lowerLimit\":0,\"upperCondition\":\"No Upper Limit\",\"upperLimit\":0,\"amount\":\"X*0.055\",\"id\":\"rangeAmounts_1\"}]',2), - (104,'Tax - Ghana','[]','[]',NULL,'',2), - (106,'Next 108 GHC','[]','[]',112,'[{\"lowerCondition\":\"gte\",\"lowerLimit\":\"216\",\"upperCondition\":\"lt\",\"upperLimit\":\"324\",\"amount\":\"X*0.05\",\"id\":\"rangeAmounts_1\"},{\"lowerCondition\":\"gte\",\"lowerLimit\":\"324\",\"upperCondition\":\"No Upper Limit\",\"upperLimit\":0,\"amount\":\"5.4\",\"id\":\"rangeAmounts_2\"}]',2), - (107,'Next 151 GHC','[]','[]',112,'[{\"lowerCondition\":\"gte\",\"lowerLimit\":\"324\",\"upperCondition\":\"lt\",\"upperLimit\":\"475\",\"amount\":\"(X-324) * 0.1\",\"id\":\"rangeAmounts_1\"},{\"lowerCondition\":\"gte\",\"lowerLimit\":\"259\",\"upperCondition\":\"No Upper Limit\",\"upperLimit\":0,\"amount\":\"15.10\",\"id\":\"rangeAmounts_2\"}]',2), - (108,'Next 2765 GHC','[]','[]',112,'[{\"lowerCondition\":\"gte\",\"lowerLimit\":\"475\",\"upperCondition\":\"lt\",\"upperLimit\":\"3240\",\"amount\":\"(X - 475) * 0.175\",\"id\":\"rangeAmounts_1\"},{\"lowerCondition\":\"gte\",\"lowerLimit\":\"3240\",\"upperCondition\":\"No Upper Limit\",\"upperLimit\":0,\"amount\":\"483.88\",\"id\":\"rangeAmounts_2\"}]',2), - (111,'Remaining after 3240 GHC','[]','[]',112,'[{\"lowerCondition\":\"gte\",\"lowerLimit\":\"3240\",\"upperCondition\":\"No Upper Limit\",\"upperLimit\":0,\"amount\":\"(X-3240)*0.25\",\"id\":\"rangeAmounts_1\"}]',2); - From 03ae79f1f14a09ae95812cb3251fe71db177a187 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Tue, 10 Oct 2017 23:40:35 +0200 Subject: [PATCH 08/21] Fix LDAP login --- login.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/login.php b/login.php index 15696513..84884570 100644 --- a/login.php +++ b/login.php @@ -22,6 +22,25 @@ if (empty($user)) { } if (!empty($_REQUEST['username']) && !empty($_REQUEST['password'])) { + + if($_REQUEST['username'] != "admin") { + if (\Classes\SettingsManager::getInstance()->getSetting("LDAP: Enabled") == "1") { + $ldapResp = \Classes\LDAPManager::getInstance()->checkLDAPLogin($_REQUEST['username'], $_REQUEST['password']); + if ($ldapResp->getStatus() == \Classes\IceResponse::ERROR) { + header("Location:" . CLIENT_BASE_URL . "login.php?f=1"); + exit(); + } else { + $suser = new \Users\Common\Model\User(); + $suser->Load("username = ?", array($_REQUEST['username'])); + if (empty($suser)) { + header("Location:" . CLIENT_BASE_URL . "login.php?f=1"); + exit(); + } + $ssoUserLoaded = true; + } + } + } + if (!isset($_REQUEST['hashedPwd'])) { $_REQUEST['hashedPwd'] = md5($_REQUEST['password']); } From 452cda0b50c632b480b5bea7b71bca83e8acee91 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Wed, 11 Oct 2017 00:40:02 +0200 Subject: [PATCH 09/21] Fix LDAP login, sso user issue --- login.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/login.php b/login.php index 84884570..7436c522 100644 --- a/login.php +++ b/login.php @@ -22,6 +22,8 @@ if (empty($user)) { } if (!empty($_REQUEST['username']) && !empty($_REQUEST['password'])) { + $suser = null; + $ssoUserLoaded = false; if($_REQUEST['username'] != "admin") { if (\Classes\SettingsManager::getInstance()->getSetting("LDAP: Enabled") == "1") { @@ -44,8 +46,7 @@ if (empty($user)) { if (!isset($_REQUEST['hashedPwd'])) { $_REQUEST['hashedPwd'] = md5($_REQUEST['password']); } - $suser = null; - $ssoUserLoaded = false; + include 'login.com.inc.php'; From 17f9d23e31e824ec876920cef75ead1239e77699 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Tue, 31 Oct 2017 07:48:13 +0100 Subject: [PATCH 10/21] Remove unwanted logs --- login.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/login.php b/login.php index 7436c522..a1363034 100644 --- a/login.php +++ b/login.php @@ -4,8 +4,6 @@ include("config.base.php"); include("include.common.php"); include("server.includes.inc.php"); -error_log(print_r($_REQUEST, true)); - if (empty($user)) { if (!isset($_REQUEST['f']) && isset($_COOKIE['icehrmLF']) && $_REQUEST['login'] != 'no' && !isset($_REQUEST['username'])) { From 732a2d7aa3f74e0352886b4289082cb5c4a0d44e Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sat, 25 Nov 2017 20:16:06 +0100 Subject: [PATCH 11/21] Attendance and Employee API --- app/api/.htaccess | 12 + app/api/index.php | 3 + modules/employees/index.php | 30 +++ modules/employees/lib.js | 33 +++ rest.php | 2 +- scripts/icehrm_master_data.sql | 9 - service.php | 9 +- .../Admin/Api/AttendanceAdminManager.php | 44 ++++ .../User/Api/AttendanceActionManager.php | 5 +- src/Classes/BaseService.php | 39 ++- src/Classes/CustomFieldManager.php | 4 + src/Classes/IceResponse.php | 24 ++ src/Classes/RestApiManager.php | 6 +- src/Classes/RestEndPoint.php | 238 ++++++++++++++++-- .../Admin/Api/EmployeesAdminManager.php | 27 +- src/Employees/Rest/EmployeeRestEndPoint.php | 157 +++++++++--- 16 files changed, 560 insertions(+), 82 deletions(-) create mode 100644 app/api/.htaccess create mode 100644 app/api/index.php diff --git a/app/api/.htaccess b/app/api/.htaccess new file mode 100644 index 00000000..166e0251 --- /dev/null +++ b/app/api/.htaccess @@ -0,0 +1,12 @@ + + Options +FollowSymlinks + RewriteEngine On + + # Explicitly disable rewriting for front controllers + RewriteRule ^index.php - [L] + + RewriteCond %{REQUEST_FILENAME} !-f + + # Change below before deploying to production + RewriteRule ^(.*)$ index.php [QSA,L] + diff --git a/app/api/index.php b/app/api/index.php new file mode 100644 index 00000000..04b20b4c --- /dev/null +++ b/app/api/index.php @@ -0,0 +1,3 @@ +getFieldNameMappings("Employee"); $customFields = \Classes\BaseService::getInstance()->getCustomFields("Employee"); + +if (\Classes\SettingsManager::getInstance()->getSetting("Api: REST Api Enabled") == "1") { + $user = \Classes\BaseService::getInstance()->getCurrentUser(); + if (empty($user)) { + return; + } + $dbUser = new \Users\Common\Model\User(); + $dbUser->Load("id = ?", array($user->id)); + $resp = \Classes\RestApiManager::getInstance()->getAccessTokenForUser($dbUser); + if ($resp->getStatus() != \Classes\IceResponse::SUCCESS) { + \Utils\LogManager::getInstance()->error( + "Error occurred while creating REST Api access token for ".$user->username + ); + } +} ?> @@ -56,6 +71,9 @@ path.link {
@@ -70,6 +88,17 @@ path.link {
+ getSetting("Api: REST Api Enabled") == "1") { ?> +
+
+
+

Api Access Token

+
+ getData()?> +
+
+
+
@@ -79,6 +108,7 @@ modJsList['tabEmployee'] = new EmployeeAdapter('Employee'); modJsList['tabEmployee'].setFieldNameMap(); modJsList['tabEmployee'].setCustomFields(); modJsList['tabCompanyGraph'] = new CompanyGraphAdapter('CompanyStructure'); +modJsList['tabApiAccess'] = new ApiAccessAdapter('ApiAccess'); var modJs = modJsList['tabEmployee']; diff --git a/modules/employees/lib.js b/modules/employees/lib.js index e796a8c8..cccb69dc 100644 --- a/modules/employees/lib.js +++ b/modules/employees/lib.js @@ -710,3 +710,36 @@ CompanyGraphAdapter.method('fixCyclicParent', function(sourceData) { }); + + +/* + * Api Access + */ + +function ApiAccessAdapter(endPoint) { + this.initAdapter(endPoint); +} + +ApiAccessAdapter.inherits(AdapterBase); + + + +ApiAccessAdapter.method('getDataMapping', function() { + return [ + ]; +}); + +ApiAccessAdapter.method('getHeaders', function() { + return [ + + ]; +}); + +ApiAccessAdapter.method('getFormFields', function() { + return [ + ]; +}); + +ApiAccessAdapter.method('get', function() { + +}); diff --git a/rest.php b/rest.php index 2c4ab871..4f705bfc 100644 --- a/rest.php +++ b/rest.php @@ -11,7 +11,7 @@ if(\Classes\SettingsManager::getInstance()->getSetting('Api: REST Api Enabled') if (defined('SYM_CLIENT')) { define('REST_API_PATH', '/'.SYM_CLIENT.'/'); } else { - define('REST_API_PATH', '/Api/'); + define('REST_API_PATH', '/'); } diff --git a/scripts/icehrm_master_data.sql b/scripts/icehrm_master_data.sql index 132d2430..1a053f67 100644 --- a/scripts/icehrm_master_data.sql +++ b/scripts/icehrm_master_data.sql @@ -1449,17 +1449,8 @@ INSERT INTO `ExpensesCategories` (`name`) VALUES ('Utility'); -INSERT INTO `PayrollColumns` (`id`,`name`,`calculation_hook`,`salary_components`,`deductions`,`add_columns`,`sub_columns`,`editable`,`enabled`,`default_value`,`calculation_columns`,`calculation_function`) VALUES - (1,'Total Hours','AttendanceUtil_getTimeWorkedHours','','','','','No','Yes','0.00',NULL,NULL), - (2,'Regular Hours','AttendanceUtil_getRegularWorkedHours','','','','','No','Yes','0.00',NULL,NULL), - (3,'Overtime Hours','AttendanceUtil_getOverTimeWorkedHours','','','','','No','Yes','0.00',NULL,NULL), - (4,'Leave Hours','LeaveUtil_getLeaveHours','','','','','No','Yes','0.00',NULL,NULL); -INSERT INTO `PayrollColumnTemplates` (`name`,`columns`) VALUES - ('All Columns','[\"1\",\"2\",\"3\",\"4\"]'), - ('All Time Management Columns','[\"1\",\"2\",\"3\"]'); - INSERT INTO `DataImport` (`name`, `dataType`, `details`, `columns`, `updated`, `created`) VALUES diff --git a/service.php b/service.php index 3f967fb9..2addf8b1 100644 --- a/service.php +++ b/service.php @@ -78,11 +78,12 @@ if($action == 'get'){ }else if($action == 'delete'){ - $ret['object'] = \Classes\BaseService::getInstance()->deleteElement($_REQUEST['t'],$_REQUEST['id']); - if($ret['object'] == null){ - $ret['status'] = "SUCCESS"; + /* @var \Classes\IceResponse $response */ + $response = \Classes\BaseService::getInstance()->deleteElement($_REQUEST['t'],$_REQUEST['id']); + if($response->getStatus() == \Classes\IceResponse::SUCCESS){ + $ret['status'] = \Classes\IceResponse::SUCCESS; }else{ - $ret['status'] = "ERROR"; + $ret['status'] = \Classes\IceResponse::ERROR; } }else if($action == 'getFieldValues'){ diff --git a/src/Attendance/Admin/Api/AttendanceAdminManager.php b/src/Attendance/Admin/Api/AttendanceAdminManager.php index 90f7c865..42f0c178 100644 --- a/src/Attendance/Admin/Api/AttendanceAdminManager.php +++ b/src/Attendance/Admin/Api/AttendanceAdminManager.php @@ -2,6 +2,7 @@ namespace Attendance\Admin\Api; use Attendance\Common\Model\Attendance; +use Attendance\Rest\AttendanceRestEndPoint; use Classes\AbstractModuleManager; use Classes\UIManager; @@ -26,6 +27,49 @@ class AttendanceAdminManager extends AbstractModuleManager $this->addModelClass('AttendanceStatus'); } + public function setupRestEndPoints() + { + \Classes\Macaw::get(REST_API_PATH.'attendance/(:num)', function ($pathParams) { + $restEndPoint = new AttendanceRestEndPoint(); + $restEndPoint->process('get', $pathParams); + }); + + \Classes\Macaw::get(REST_API_PATH.'attendance', function ($pathParams) { + $restEndPoint = new AttendanceRestEndPoint(); + $restEndPoint->process('list', $pathParams); + }); + + \Classes\Macaw::get(REST_API_PATH.'employee/(:num)/attendance', function ($pathParams) { + $restEndPoint = new AttendanceRestEndPoint(); + $restEndPoint->process('listEmployeeAttendance', $pathParams); + }); + + \Classes\Macaw::post(REST_API_PATH.'attendance', function ($pathParams) { + $restEndPoint = new AttendanceRestEndPoint(); + $restEndPoint->process('post', $pathParams); + }); + + \Classes\Macaw::delete(REST_API_PATH.'attendance/(:num)', function ($pathParams) { + $restEndPoint = new AttendanceRestEndPoint(); + $restEndPoint->process('delete', $pathParams); + }); + + \Classes\Macaw::post(REST_API_PATH.'attendance/punch-in', function ($pathParams) { + $restEndPoint = new AttendanceRestEndPoint(); + $restEndPoint->process('punchIn', $pathParams); + }); + + \Classes\Macaw::get(REST_API_PATH.'employee/(:num)/open-punch-in/(:any)', function ($employeeId, $date) { + $restEndPoint = new AttendanceRestEndPoint(); + $restEndPoint->process('getOpenPunch', [$employeeId, $date]); + }); + + \Classes\Macaw::post(REST_API_PATH.'attendance/punch-out', function ($pathParams) { + $restEndPoint = new AttendanceRestEndPoint(); + $restEndPoint->process('punchOut', $pathParams); + }); + } + public function getDashboardItemData() { $data = array(); diff --git a/src/Attendance/User/Api/AttendanceActionManager.php b/src/Attendance/User/Api/AttendanceActionManager.php index 39730f65..07407134 100644 --- a/src/Attendance/User/Api/AttendanceActionManager.php +++ b/src/Attendance/User/Api/AttendanceActionManager.php @@ -32,8 +32,8 @@ class AttendanceActionManager extends SubActionManager //Find any open punch $attendance = new Attendance(); $attendance->Load( - "employee = ? and DATE_FORMAT( in_time, '%Y-%m-%d' ) = ? - and (out_time is NULL or out_time = '0000-00-00 00:00:00')", + "employee = ? and DATE_FORMAT( in_time, '%Y-%m-%d' ) = ? and (out_time is NULL + or out_time = '0000-00-00 00:00:00')", array($employee->id,$date) ); @@ -135,6 +135,7 @@ class AttendanceActionManager extends SubActionManager $this->baseService->audit(IceConstants::AUDIT_ACTION, "Punch Out \ time:".$openPunch->out_time); } else { $openPunch->in_time = $dateTime; + //$openPunch->out_time = '0000-00-00 00:00:00'; $openPunch->note = $req->note; $openPunch->image_in = $req->image; $openPunch->employee = $employee->id; diff --git a/src/Classes/BaseService.php b/src/Classes/BaseService.php index 1d8f2316..c3afc669 100644 --- a/src/Classes/BaseService.php +++ b/src/Classes/BaseService.php @@ -72,6 +72,7 @@ class BaseService public $customFieldManager = null; public $migrationManager = null; public $modelClassMap = array(); + public $currentProfileId = false; private static $me = null; @@ -187,6 +188,14 @@ class BaseService return $this->getFullQualifiedModelClassName($name); } + /** + * @param boolean $currentProfileId + */ + public function setCurrentProfileId($currentProfileId) + { + $this->currentProfileId = $currentProfileId; + } + public function buildDefaultFilterQuery($filter) { $query = ""; @@ -755,9 +764,7 @@ class BaseService } return new IceResponse(IceResponse::ERROR, $this->findError($error)); } - LogManager::getInstance()->error("Element:".json_encode($ele)); - LogManager::getInstance()->error("Obj:".json_encode($obj)); - LogManager::getInstance()->error("Obj Keys:".json_encode($objectKeys)); + $customFields = $ele->getCustomFields($obj); LogManager::getInstance()->error("Custom:".json_encode($customFields)); foreach ($obj as $k => $v) { @@ -792,6 +799,13 @@ class BaseService $ele = new $nsTable(); $ele->Load('id = ?', array($id)); + if (empty($ele->id) || $ele->id !== $id) { + return new IceResponse( + IceResponse::ERROR, + "Item not found" + ); + } + $this->checkSecureAccess("delete", $ele); @@ -800,7 +814,10 @@ class BaseService if (!empty($nonDeletableTable)) { foreach ($nonDeletableTable as $field => $value) { if ($ele->$field == $value) { - return "This item can not be deleted"; + return new IceResponse( + IceResponse::ERROR, + "This item can not be deleted" + ); } } } @@ -818,7 +835,10 @@ class BaseService if (!$ok) { $error = $ele->ErrorMsg(); LogManager::getInstance()->info($error); - return $this->findError($error); + return new IceResponse( + IceResponse::ERROR, + $this->findError($error) + ); } else { //Backup if ($table == ucfirst(SIGN_IN_ELEMENT_MAPPING_FIELD_NAME)) { @@ -845,7 +865,10 @@ class BaseService $cf->Delete(); } - return null; + return new IceResponse( + IceResponse::SUCCESS, + null + ); } /** @@ -974,6 +997,9 @@ class BaseService */ public function getCurrentProfileId() { + if ($this->currentProfileId) { + return $this->currentProfileId; + } $adminEmpId = SessionUtils::getSessionObject('admin_current_profile'); $user = SessionUtils::getSessionObject('user'); if (empty($adminEmpId) && !empty($user)) { @@ -1035,6 +1061,7 @@ class BaseService public function cleanUpAdoDB($obj) { + unset($obj->table); unset($obj->_table); unset($obj->_dbat); unset($obj->_tableat); diff --git a/src/Classes/CustomFieldManager.php b/src/Classes/CustomFieldManager.php index 035643ce..b68463c3 100644 --- a/src/Classes/CustomFieldManager.php +++ b/src/Classes/CustomFieldManager.php @@ -14,6 +14,10 @@ class CustomFieldManager { public function addCustomField($type, $id, $name, $value) { + if ($name[0] === '/') { + return; + } + $customFieldValue = new CustomFieldValue(); $customFieldValue->Load( "type = ? and name = ? and object_id = ?", diff --git a/src/Classes/IceResponse.php b/src/Classes/IceResponse.php index 8a85c325..b1db319e 100644 --- a/src/Classes/IceResponse.php +++ b/src/Classes/IceResponse.php @@ -49,4 +49,28 @@ class IceResponse { return array("status"=>$this->status,"data"=>$this->data); } + + /** + * @param mixed $status + */ + public function setStatus($status) + { + $this->status = $status; + } + + /** + * @param null $data + */ + public function setData($data) + { + $this->data = $data; + } + + /** + * @param null $code + */ + public function setCode($code) + { + $this->code = $code; + } } diff --git a/src/Classes/RestApiManager.php b/src/Classes/RestApiManager.php index 0158b638..b0ed8584 100644 --- a/src/Classes/RestApiManager.php +++ b/src/Classes/RestApiManager.php @@ -85,8 +85,7 @@ class RestApiManager LogManager::getInstance()->info("AT Hash Object:".json_encode($accessTokenObj)); if (!empty($accessTokenObj->id) && $accessTokenObj->hash == $hash) { //No need to do user based validation for now - //return $this->validateAccessTokenInner($accessTokenObj->token); - return new IceResponse(IceResponse::SUCCESS, true); + return $this->validateAccessTokenInner($accessTokenObj->token); } return new IceResponse(IceResponse::ERROR, "Authorization bearer token not found or invalid", 401); @@ -107,7 +106,8 @@ class RestApiManager $data = json_decode($accessToken, true); if ($data['userId'] == $user->id) { - return new IceResponse(IceResponse::SUCCESS, true); + unset($user->password); + return new IceResponse(IceResponse::SUCCESS, $user); } return new IceResponse(IceResponse::ERROR, false); diff --git a/src/Classes/RestEndPoint.php b/src/Classes/RestEndPoint.php index 6a9a9400..e10a68d9 100644 --- a/src/Classes/RestEndPoint.php +++ b/src/Classes/RestEndPoint.php @@ -1,24 +1,74 @@ Load("id = ?", array($employeeId)); + if (empty($employee->id) || $employee->id !== $employeeId . '') { + return new IceResponse(IceResponse::ERROR, self::RESPONSE_ERR_EMPLOYEE_NOT_FOUND, 422); + } + + if ($user->user_level !== 'Admin') { + if ($user->user_level === 'Manager') { + if (!PermissionManager::manipulationAllowed( + BaseService::getInstance()->getCurrentProfileId(), + $employee + ) + ) { + return new IceResponse(IceResponse::ERROR, self::RESPONSE_ERR_PERMISSION_DENIED, 403); + } + } elseif ($user->user_level === 'Employee' + && $employeeId != BaseService::getInstance()->getCurrentProfileId()) { + return new IceResponse(IceResponse::ERROR, self::RESPONSE_ERR_PERMISSION_DENIED, 403); + } elseif ($user->user_level !== 'Employee' && $user->user_level !== 'Manager') { + return new IceResponse(IceResponse::ERROR, self::RESPONSE_ERR_PERMISSION_DENIED, 403); + } + return new IceResponse(IceResponse::ERROR, "Permission denied", 403); + } + + return new IceResponse(IceResponse::SUCCESS); + } + + public function process($type, $parameters = []) + { + if (!is_array($parameters)) { + $parameters = [$parameters]; + } $accessTokenValidation = $this->validateAccessToken(); if (!empty($accessTokenValidation) && $accessTokenValidation->getStatus() == IceResponse::ERROR) { $resp = $accessTokenValidation; } else { - $resp = $this->$type($parameter); + BaseService::getInstance()->setCurrentUser($accessTokenValidation->getData()); + SessionUtils::saveSessionObject('user', $accessTokenValidation->getData()); + array_unshift($parameters, $accessTokenValidation->getData()); + $resp = call_user_func_array(array($this, $type), $parameters); } header('Content-Type: application/json'); @@ -39,33 +89,177 @@ class RestEndPoint "code" => $resp->getCode(), "message" => $resp->getObject() ); - $this->printResponse(array("error",[$messages])); + $this->printResponse(array("error" => [$messages])); } } - public function get($parameter) + protected function enrichElement($obj, $map) + { + if (!empty($map)) { + foreach ($map as $k => $v) { + if ($obj->$k !== null) { + $obj->$k = [ + 'type' => $v[0], + $v[1] => $obj->$k, + 'display' => $obj->{$k . '_Name'} + ]; + } else { + unset($obj->$k); + } + unset($obj->{$k . '_Name'}); + } + } + return $obj; + } + + protected function cleanObject($obj) + { + $obj = BaseService::getInstance()->cleanUpAdoDB($obj); + unset($obj->keysToIgnore); + unset($obj->historyFieldsToTrack); + unset($obj->historyUpdateList); + unset($obj->oldObjOrig); + unset($obj->oldObj); + + return $obj; + } + + protected function removeNullFields($obj) + { + foreach ($obj as $k => $v) { + if ($obj->$k === null) { + unset($obj->$k); + } + } + + return $obj; + } + + public function list(User $user) { return new IceResponse(IceResponse::ERROR, "Method not Implemented", 404); } - public function post($parameter) + protected function listByQuery(DataQuery $query) + { + $page = 1; + if (isset($_GET['page']) && intval($_GET['page']) > 0) { + $page = intval($_GET['page']); + } + + $limit = static::DEFAULT_LIMIT; + if (isset($_GET['limit']) && intval($_GET['limit']) > 0) { + $limit = intval($_GET['limit']); + } + + $query->setStartPage(($page - 1) * $limit); + $query->setLength($limit); + + $data = DataReader::getData($query); + $output = array(); + $columns = $query->getColumns(); + foreach ($data as $item) { + if (!empty($columns)) { + $obj = new \stdClass(); + foreach ($columns as $column) { + $obj->$column = $item->$column; + } + } else { + $obj = $this->cleanObject($item); + } + $output[] = $obj; + } + + return new IceResponse( + IceResponse::SUCCESS, + [ + 'data' => $output, + 'nextPage' => $page + 1, + ] + ); + } + + protected function listData( + $object, + $limit, + $page = 1, + $fieldsToRemove = array(), + $customQuery = null, + $params = [] + ) { + if (!isset($limit) || $limit <= 0) { + $limit = self::DEFAULT_LIMIT; + } + + if ($customQuery) { + $query = $customQuery.' order by id limit ?,?'; + $params[] = ($page - 1) * $limit; + $params[] = $limit + 1; + } else { + $query = '1=1 order by id limit ?,?'; + $params = array(($page - 1) * $limit, ($limit + 1)); + } + + $allObjects = $object->Find($query, $params); + $count = 0; + $hasMore = 0; + $newObjects = array(); + foreach ($allObjects as $object) { + $object = $this->cleanObject($object); + $object = $this->removeNullFields($object); + if (!empty($fieldsToRemove)) { + foreach ($fieldsToRemove as $field) { + unset($object->$field); + } + } + $newObjects[] = $object; + $count++; + if ($count === $limit) { + $hasMore = true; + break; + } + } + + return new IceResponse( + IceResponse::SUCCESS, + [ + 'data' => $newObjects, + 'prevPage' => ($page > 1) ? $page - 1 : '', + 'nextPage' => $hasMore ? $page + 1 : '', + 'limit' => $limit, + ] + ); + } + + public function get(User $user, $parameter) { return new IceResponse(IceResponse::ERROR, "Method not Implemented", 404); } - public function put($parameter) + public function post(User $user) { return new IceResponse(IceResponse::ERROR, "Method not Implemented", 404); } - public function delete($parameter) + public function put(User $user, $parameter) { return new IceResponse(IceResponse::ERROR, "Method not Implemented", 404); } - public function clearObject($obj) + public function delete(User $user, $parameter) { - return BaseService::getInstance()->cleanUpAdoDB($obj); + if ($user->user_level !== 'Admin') { + return new IceResponse(IceResponse::ERROR, "Permission denied", 403); + } + + $response = BaseService::getInstance()->deleteElement( + static::ELEMENT_NAME, + $parameter + ); + if ($response->getStatus() === IceResponse::SUCCESS) { + return new IceResponse(IceResponse::SUCCESS, ['id' => $parameter], 200); + } + return new IceResponse(IceResponse::ERROR, $response->getData(), 400); } public function validateAccessToken() @@ -75,12 +269,6 @@ class RestEndPoint return $accessTokenValidation; } - public function cleanDBObject($obj) - { - unset($obj->keysToIgnore); - return $obj; - } - public function printResponse($response) { echo json_encode($response, JSON_PRETTY_PRINT); @@ -129,4 +317,10 @@ class RestEndPoint } return null; } + + protected function getRequestBody() + { + $inputJSON = file_get_contents('php://input'); + return json_decode($inputJSON, true); + } } diff --git a/src/Employees/Admin/Api/EmployeesAdminManager.php b/src/Employees/Admin/Api/EmployeesAdminManager.php index aa629ad8..1e1dc95f 100644 --- a/src/Employees/Admin/Api/EmployeesAdminManager.php +++ b/src/Employees/Admin/Api/EmployeesAdminManager.php @@ -26,10 +26,35 @@ class EmployeesAdminManager extends AbstractModuleManager public function setupRestEndPoints() { - \Classes\Macaw::get(REST_API_PATH.'employee/(:any)', function ($pathParams) { + \Classes\Macaw::get(REST_API_PATH.'employees/me', function () { + $empRestEndPoint = new EmployeeRestEndPoint(); + $empRestEndPoint->process('get', 'me'); + }); + + \Classes\Macaw::get(REST_API_PATH.'employees/(:num)', function ($pathParams) { $empRestEndPoint = new EmployeeRestEndPoint(); $empRestEndPoint->process('get', $pathParams); }); + + \Classes\Macaw::get(REST_API_PATH.'employees', function () { + $empRestEndPoint = new EmployeeRestEndPoint(); + $empRestEndPoint->process('list'); + }); + + \Classes\Macaw::post(REST_API_PATH.'employees', function () { + $empRestEndPoint = new EmployeeRestEndPoint(); + $empRestEndPoint->process('post'); + }); + + \Classes\Macaw::put(REST_API_PATH.'employees/(:num)', function ($pathParams) { + $empRestEndPoint = new EmployeeRestEndPoint(); + $empRestEndPoint->process('put', $pathParams); + }); + + \Classes\Macaw::delete(REST_API_PATH.'employees/(:num)', function ($pathParams) { + $empRestEndPoint = new EmployeeRestEndPoint(); + $empRestEndPoint->process('delete', $pathParams); + }); } public function initializeDatabaseErrorMappings() diff --git a/src/Employees/Rest/EmployeeRestEndPoint.php b/src/Employees/Rest/EmployeeRestEndPoint.php index 970c7d40..891b578a 100644 --- a/src/Employees/Rest/EmployeeRestEndPoint.php +++ b/src/Employees/Rest/EmployeeRestEndPoint.php @@ -1,51 +1,140 @@ Load("id = ?", array($id)); + return $obj; + } + + public function list(User $user) + { + $query = new DataQuery('Employee'); + + $limit = self::DEFAULT_LIMIT; + if (isset($_GET['limit']) && intval($_GET['limit']) > 0) { + $limit = intval($_GET['limit']); + } + $query->setLength($limit); + + if ($user->user_level !== 'Admin') { + $query->setIsSubOrdinates(true); } - if ($parameter === 'list') { - $emp = new Employee(); - $emps = $emp->Find("1=1"); - $newEmps = array(); - foreach ($emps as $emp) { - $emp = BaseService::getInstance()->cleanUpAdoDB($emp); - $emp = Employee::cleanEmployeeData($emp); - $newEmps[] = $emp; - } - return new IceResponse(IceResponse::SUCCESS, $newEmps); - } else { - $mapping = '{"nationality":["Nationality","id","name"],"ethnicity":["Ethnicity","id","name"],' - .'"immigration_status":["ImmigrationStatus","id","name"],' - .'"employment_status":["EmploymentStatus","id","name"],' - .'"job_title":["JobTitle","id","name"],"pay_grade":["PayGrade","id","name"],' - .'"country":["Country","code","name"],"province":["Province","id","name"],' - .'"department":["CompanyStructure","id","title"],' - .'"supervisor":["Employee","id","first_name+last_name"]}'; - $emp = BaseService::getInstance()->getElement('Employee', $parameter, $mapping, true); - if (!empty($emp)) { - $emp = Employee::cleanEmployeeData($emp); - return new IceResponse(IceResponse::SUCCESS, $emp); - } + return $this->listByQuery($query); + } + + public function get(User $user, $parameter) + { + if (empty($parameter)) { return new IceResponse(IceResponse::ERROR, "Employee not found", 404); } + + if ($parameter === 'me') { + $parameter = BaseService::getInstance()->getCurrentProfileId(); + } + + if ($user->user_level !== 'Admin' && !PermissionManager::manipulationAllowed( + BaseService::getInstance()->getCurrentProfileId(), + $this->getModelObject($parameter) + ) + ) { + return new IceResponse(IceResponse::ERROR, "Permission denied", 403); + } + + $mapping = [ + "nationality" => ["Nationality","id","name"], + "ethnicity" => ["Ethnicity","id","name"], + "immigration_status" => ["ImmigrationStatus","id","name"], + "employment_status" => ["EmploymentStatus","id","name"], + "job_title" => ["JobTitle","id","name"], + "pay_grade" => ["PayGrade","id","name"], + "country" => ["Country","code","name"], + "province" => ["Province","id","name"], + "department" => ["CompanyStructure","id","title"], + "supervisor" => [self::ELEMENT_NAME,"id","first_name+last_name"], + ]; + + $emp = BaseService::getInstance()->getElement( + self::ELEMENT_NAME, + $parameter, + json_encode($mapping), + true + ); + + $emp = $this->enrichElement($emp, $mapping); + if (!empty($emp)) { + $emp = $this->cleanObject($emp); + $emp = $this->removeNullFields($emp); + return new IceResponse(IceResponse::SUCCESS, $emp); + } + return new IceResponse(IceResponse::ERROR, "Employee not found", 404); + } + + public function post(User $user) + { + if ($user->user_level !== 'Admin') { + return new IceResponse(IceResponse::ERROR, "Permission denied", 403); + } + $body = $this->getRequestBody(); + $response = BaseService::getInstance()->addElement(self::ELEMENT_NAME, $body); + if ($response->getStatus() === IceResponse::SUCCESS) { + $response = $this->get($user, $response->getData()->id); + $response->setCode(201); + return $response; + } + + return new IceResponse(IceResponse::ERROR, $response->getData(), 400); + } + + public function put(User $user, $parameter) + { + + if ($user->user_level !== 'Admin' && + !PermissionManager::manipulationAllowed( + BaseService::getInstance()->getCurrentProfileId(), + $this->getModelObject($parameter) + ) + ) { + return new IceResponse(IceResponse::ERROR, "Permission denied", 403); + } + + $body = $this->getRequestBody(); + $body['id'] = $parameter; + $response = BaseService::getInstance()->addElement(self::ELEMENT_NAME, $body); + if ($response->getStatus() === IceResponse::SUCCESS) { + return $this->get($user, $response->getData()->id); + } + + return new IceResponse(IceResponse::ERROR, 'Error modifying employee', 400); + } + + public function delete(User $user, $parameter) + { + if ($user->user_level !== 'Admin') { + return new IceResponse(IceResponse::ERROR, "Permission denied", 403); + } + + $response = BaseService::getInstance()->deleteElement( + self::ELEMENT_NAME, + $parameter + ); + if ($response->getStatus() === IceResponse::SUCCESS) { + return new IceResponse(IceResponse::SUCCESS, ['id' => $parameter], 200); + } + return new IceResponse(IceResponse::ERROR, $response->getData(), 400); } } From 7330194eb32c4f322e7da84ff92f271811ef4ccc Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sat, 25 Nov 2017 20:19:18 +0100 Subject: [PATCH 12/21] Payroll hooks for timesheet --- .../Admin/Api/ExpensesAdminManager.php | 18 ++++++++++-------- .../Common/Model/EmployeeTimeSheet.php | 11 +++++++++-- .../User/Api/TimeSheetsModulesManager.php | 10 ++++++++++ 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/Expenses/Admin/Api/ExpensesAdminManager.php b/src/Expenses/Admin/Api/ExpensesAdminManager.php index 396b7094..2323a07a 100644 --- a/src/Expenses/Admin/Api/ExpensesAdminManager.php +++ b/src/Expenses/Admin/Api/ExpensesAdminManager.php @@ -1,11 +1,4 @@ addFileFieldMapping('EmployeeExpense', 'attachment1', 'name'); $this->addFileFieldMapping('EmployeeExpense', 'attachment2', 'name'); $this->addFileFieldMapping('EmployeeExpense', 'attachment3', 'name'); @@ -40,4 +32,14 @@ class ExpensesAdminManager extends AbstractModuleManager $this->addModelClass('EmployeeExpense'); $this->addModelClass('EmployeeExpenseApproval'); } + + public function initCalculationHooks() + { + $this->addCalculationHook( + 'ExpensePayrollUtils_getApprovedExpensesTotal', + 'Total Approved Expenses', + ExpensePayrollUtils::class, + 'getApprovedExpensesTotal' + ); + } } diff --git a/src/TimeSheets/Common/Model/EmployeeTimeSheet.php b/src/TimeSheets/Common/Model/EmployeeTimeSheet.php index 15db9227..68ee5315 100644 --- a/src/TimeSheets/Common/Model/EmployeeTimeSheet.php +++ b/src/TimeSheets/Common/Model/EmployeeTimeSheet.php @@ -35,7 +35,7 @@ class EmployeeTimeSheet extends BaseModel return array("element","save","delete"); } - public function getTotalTime() + public function getTotalTimeMinutes() { $start = $this->date_start . " 00:00:00"; @@ -59,11 +59,18 @@ class EmployeeTimeSheet extends BaseModel } $totMinutes = round($seconds / 60); + + return $totMinutes; + } + + public function getTotalTime() + { + $totMinutes = $this->getTotalTimeMinutes(); $minutes = $totMinutes % 60; $hours = ($totMinutes - $minutes) / 60; return CalendarTools::addLeadingZero($hours) - . ":" . CalendarTools::addLeadingZero($minutes); + . ":" . CalendarTools::addLeadingZero($minutes); } public function postProcessGetData($entry) diff --git a/src/TimeSheets/User/Api/TimeSheetsModulesManager.php b/src/TimeSheets/User/Api/TimeSheetsModulesManager.php index 26bb8470..85896734 100644 --- a/src/TimeSheets/User/Api/TimeSheetsModulesManager.php +++ b/src/TimeSheets/User/Api/TimeSheetsModulesManager.php @@ -79,4 +79,14 @@ class TimeSheetsModulesManager extends AbstractModuleManager } return new IceResponse(IceResponse::SUCCESS, $hours.":".$rem); } + + public function initCalculationHooks() + { + $this->addCalculationHook( + 'TimeSheetsPayrollUtils_getApprovedTimeInTimeSheets', + 'Total Hours from Approved Time Sheets', + TimeSheetsPayrollUtils::class, + 'getApprovedTimeInTimeSheets' + ); + } } From 83181beb23e56279af7db53fdd3812b94c05dfa3 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 26 Nov 2017 18:20:25 +0100 Subject: [PATCH 13/21] Adding swift mailer --- admin/users/lib.js | 47 +- lib/composer/composer.json | 3 +- lib/composer/composer.lock | 171 +- lib/composer/vendor/autoload.php | 2 +- lib/composer/vendor/composer/ClassLoader.php | 8 +- .../vendor/composer/autoload_files.php | 3 +- .../vendor/composer/autoload_namespaces.php | 1 + .../vendor/composer/autoload_psr4.php | 1 + .../vendor/composer/autoload_real.php | 53 +- .../vendor/composer/autoload_static.php | 36 +- lib/composer/vendor/composer/installed.json | 172 ++ lib/composer/vendor/doctrine/lexer/LICENSE | 19 + lib/composer/vendor/doctrine/lexer/README.md | 5 + .../vendor/doctrine/lexer/composer.json | 24 + .../Doctrine/Common/Lexer/AbstractLexer.php | 327 +++ .../EmailValidator/EmailLexer.php | 221 ++ .../EmailValidator/EmailParser.php | 104 + .../EmailValidator/EmailValidator.php | 67 + .../Exception/AtextAfterCFWS.php | 9 + .../EmailValidator/Exception/CRLFAtTheEnd.php | 9 + .../EmailValidator/Exception/CRLFX2.php | 9 + .../EmailValidator/Exception/CRNoLF.php | 9 + .../Exception/CharNotAllowed.php | 9 + .../Exception/CommaInDomain.php | 9 + .../Exception/ConsecutiveAt.php | 9 + .../Exception/ConsecutiveDot.php | 9 + .../Exception/DomainHyphened.php | 9 + .../EmailValidator/Exception/DotAtEnd.php | 9 + .../EmailValidator/Exception/DotAtStart.php | 9 + .../EmailValidator/Exception/ExpectingAT.php | 9 + .../Exception/ExpectingATEXT.php | 9 + .../Exception/ExpectingCTEXT.php | 9 + .../Exception/ExpectingDTEXT.php | 9 + .../Exception/ExpectingDomainLiteralClose.php | 9 + .../Exception/ExpectingQPair.php | 9 + .../EmailValidator/Exception/InvalidEmail.php | 14 + .../EmailValidator/Exception/NoDNSRecord.php | 11 + .../EmailValidator/Exception/NoDomainPart.php | 9 + .../EmailValidator/Exception/NoLocalPart.php | 9 + .../Exception/UnclosedComment.php | 9 + .../Exception/UnclosedQuotedString.php | 9 + .../Exception/UnopenedComment.php | 9 + .../EmailValidator/Parser/DomainPart.php | 368 ++++ .../EmailValidator/Parser/LocalPart.php | 138 ++ .../EmailValidator/Parser/Parser.php | 215 ++ .../Validation/DNSCheckValidation.php | 61 + .../Validation/EmailValidation.php | 34 + .../Validation/Error/RFCWarnings.php | 11 + .../Validation/Error/SpoofEmail.php | 11 + .../Exception/EmptyValidationList.php | 13 + .../Validation/MultipleErrors.php | 26 + .../Validation/MultipleValidationWithAnd.php | 110 + .../Validation/NoRFCWarningsValidation.php | 41 + .../Validation/RFCValidation.php | 49 + .../Validation/SpoofCheckValidation.php | 45 + .../EmailValidator/Warning/AddressLiteral.php | 14 + .../EmailValidator/Warning/CFWSNearAt.php | 13 + .../EmailValidator/Warning/CFWSWithFWS.php | 13 + .../EmailValidator/Warning/Comment.php | 13 + .../Warning/DeprecatedComment.php | 13 + .../EmailValidator/Warning/DomainLiteral.php | 14 + .../EmailValidator/Warning/DomainTooLong.php | 14 + .../EmailValidator/Warning/EmailTooLong.php | 15 + .../EmailValidator/Warning/IPV6BadChar.php | 14 + .../EmailValidator/Warning/IPV6ColonEnd.php | 14 + .../EmailValidator/Warning/IPV6ColonStart.php | 14 + .../EmailValidator/Warning/IPV6Deprecated.php | 14 + .../Warning/IPV6DoubleColon.php | 14 + .../EmailValidator/Warning/IPV6GroupCount.php | 14 + .../EmailValidator/Warning/IPV6MaxGroups.php | 14 + .../EmailValidator/Warning/LabelTooLong.php | 14 + .../EmailValidator/Warning/LocalTooLong.php | 15 + .../EmailValidator/Warning/NoDNSMXRecord.php | 14 + .../EmailValidator/Warning/ObsoleteDTEXT.php | 14 + .../EmailValidator/Warning/QuotedPart.php | 13 + .../EmailValidator/Warning/QuotedString.php | 13 + .../EmailValidator/Warning/TLD.php | 13 + .../EmailValidator/Warning/Warning.php | 30 + .../vendor/egulias/email-validator/LICENSE | 19 + .../vendor/egulias/email-validator/README.md | 79 + .../egulias/email-validator/composer.json | 39 + .../egulias/email-validator/composer.lock | 1813 +++++++++++++++++ .../egulias/email-validator/phpunit.xml.dist | 26 + .../swiftmailer/swiftmailer/.gitattributes | 9 + .../swiftmailer/.github/ISSUE_TEMPLATE.md | 19 + .../.github/PULL_REQUEST_TEMPLATE.md | 14 + .../vendor/swiftmailer/swiftmailer/.gitignore | 8 + .../swiftmailer/swiftmailer/.php_cs.dist | 15 + .../swiftmailer/swiftmailer/.travis.yml | 24 + .../vendor/swiftmailer/swiftmailer/CHANGES | 299 +++ .../vendor/swiftmailer/swiftmailer/LICENSE | 19 + .../vendor/swiftmailer/swiftmailer/README | 15 + .../swiftmailer/swiftmailer/composer.json | 36 + .../swiftmailer/swiftmailer/doc/headers.rst | 609 ++++++ .../swiftmailer/swiftmailer/doc/index.rst | 12 + .../swiftmailer/doc/introduction.rst | 61 + .../swiftmailer/swiftmailer/doc/japanese.rst | 19 + .../swiftmailer/swiftmailer/doc/messages.rst | 908 +++++++++ .../swiftmailer/swiftmailer/doc/plugins.rst | 337 +++ .../swiftmailer/swiftmailer/doc/sending.rst | 446 ++++ .../swiftmailer/lib/classes/Swift.php | 79 + .../lib/classes/Swift/Attachment.php | 57 + .../AbstractFilterableInputStream.php | 181 ++ .../Swift/ByteStream/ArrayByteStream.php | 182 ++ .../Swift/ByteStream/FileByteStream.php | 216 ++ .../ByteStream/TemporaryFileByteStream.php | 42 + .../lib/classes/Swift/CharacterReader.php | 67 + .../GenericFixedWidthReader.php | 97 + .../Swift/CharacterReader/UsAsciiReader.php | 84 + .../Swift/CharacterReader/Utf8Reader.php | 176 ++ .../classes/Swift/CharacterReaderFactory.php | 26 + .../SimpleCharacterReaderFactory.php | 124 ++ .../lib/classes/Swift/CharacterStream.php | 89 + .../CharacterStream/ArrayCharacterStream.php | 293 +++ .../CharacterStream/NgCharacterStream.php | 267 +++ .../lib/classes/Swift/ConfigurableSpool.php | 63 + .../lib/classes/Swift/DependencyContainer.php | 373 ++++ .../lib/classes/Swift/DependencyException.php | 27 + .../lib/classes/Swift/EmbeddedFile.php | 53 + .../swiftmailer/lib/classes/Swift/Encoder.php | 28 + .../classes/Swift/Encoder/Base64Encoder.php | 58 + .../lib/classes/Swift/Encoder/QpEncoder.php | 300 +++ .../classes/Swift/Encoder/Rfc2231Encoder.php | 92 + .../lib/classes/Swift/Events/CommandEvent.php | 65 + .../classes/Swift/Events/CommandListener.php | 24 + .../lib/classes/Swift/Events/Event.php | 38 + .../classes/Swift/Events/EventDispatcher.php | 83 + .../classes/Swift/Events/EventListener.php | 18 + .../lib/classes/Swift/Events/EventObject.php | 63 + .../classes/Swift/Events/ResponseEvent.php | 65 + .../classes/Swift/Events/ResponseListener.php | 24 + .../lib/classes/Swift/Events/SendEvent.php | 129 ++ .../lib/classes/Swift/Events/SendListener.php | 31 + .../Swift/Events/SimpleEventDispatcher.php | 156 ++ .../Swift/Events/TransportChangeEvent.php | 27 + .../Swift/Events/TransportChangeListener.php | 45 + .../Swift/Events/TransportExceptionEvent.php | 46 + .../Events/TransportExceptionListener.php | 24 + .../lib/classes/Swift/FailoverTransport.php | 33 + .../lib/classes/Swift/FileSpool.php | 208 ++ .../lib/classes/Swift/FileStream.php | 24 + .../lib/classes/Swift/Filterable.php | 32 + .../lib/classes/Swift/IdGenerator.php | 22 + .../swiftmailer/lib/classes/Swift/Image.php | 43 + .../lib/classes/Swift/InputByteStream.php | 75 + .../lib/classes/Swift/IoException.php | 29 + .../lib/classes/Swift/KeyCache.php | 105 + .../classes/Swift/KeyCache/ArrayKeyCache.php | 206 ++ .../classes/Swift/KeyCache/DiskKeyCache.php | 298 +++ .../Swift/KeyCache/KeyCacheInputStream.php | 51 + .../classes/Swift/KeyCache/NullKeyCache.php | 115 ++ .../KeyCache/SimpleKeyCacheInputStream.php | 127 ++ .../classes/Swift/LoadBalancedTransport.php | 33 + .../swiftmailer/lib/classes/Swift/Mailer.php | 102 + .../Swift/Mailer/ArrayRecipientIterator.php | 55 + .../Swift/Mailer/RecipientIterator.php | 32 + .../lib/classes/Swift/MemorySpool.php | 110 + .../swiftmailer/lib/classes/Swift/Message.php | 274 +++ .../lib/classes/Swift/Mime/Attachment.php | 149 ++ .../classes/Swift/Mime/CharsetObserver.php | 24 + .../lib/classes/Swift/Mime/ContentEncoder.php | 34 + .../ContentEncoder/Base64ContentEncoder.php | 104 + .../ContentEncoder/NativeQpContentEncoder.php | 123 ++ .../ContentEncoder/PlainContentEncoder.php | 162 ++ .../Mime/ContentEncoder/QpContentEncoder.php | 134 ++ .../ContentEncoder/QpContentEncoderProxy.php | 98 + .../Mime/ContentEncoder/RawContentEncoder.php | 64 + .../lib/classes/Swift/Mime/EmbeddedFile.php | 45 + .../classes/Swift/Mime/EncodingObserver.php | 24 + .../lib/classes/Swift/Mime/Header.php | 93 + .../lib/classes/Swift/Mime/HeaderEncoder.php | 24 + .../HeaderEncoder/Base64HeaderEncoder.php | 55 + .../Mime/HeaderEncoder/QpHeaderEncoder.php | 65 + .../Swift/Mime/Headers/AbstractHeader.php | 481 +++++ .../classes/Swift/Mime/Headers/DateHeader.php | 115 ++ .../Mime/Headers/IdentificationHeader.php | 184 ++ .../Swift/Mime/Headers/MailboxHeader.php | 359 ++++ .../Swift/Mime/Headers/OpenDKIMHeader.php | 133 ++ .../Mime/Headers/ParameterizedHeader.php | 257 +++ .../classes/Swift/Mime/Headers/PathHeader.php | 152 ++ .../Swift/Mime/Headers/UnstructuredHeader.php | 110 + .../lib/classes/Swift/Mime/IdGenerator.php | 53 + .../lib/classes/Swift/Mime/MimePart.php | 212 ++ .../Swift/Mime/SimpleHeaderFactory.php | 197 ++ .../classes/Swift/Mime/SimpleHeaderSet.php | 409 ++++ .../lib/classes/Swift/Mime/SimpleMessage.php | 655 ++++++ .../classes/Swift/Mime/SimpleMimeEntity.php | 823 ++++++++ .../lib/classes/Swift/MimePart.php | 45 + .../lib/classes/Swift/NullTransport.php | 26 + .../lib/classes/Swift/OutputByteStream.php | 46 + .../classes/Swift/Plugins/AntiFloodPlugin.php | 141 ++ .../Swift/Plugins/BandwidthMonitorPlugin.php | 164 ++ .../Swift/Plugins/Decorator/Replacements.php | 31 + .../classes/Swift/Plugins/DecoratorPlugin.php | 204 ++ .../Swift/Plugins/ImpersonatePlugin.php | 69 + .../lib/classes/Swift/Plugins/Logger.php | 36 + .../classes/Swift/Plugins/LoggerPlugin.php | 142 ++ .../Swift/Plugins/Loggers/ArrayLogger.php | 72 + .../Swift/Plugins/Loggers/EchoLogger.php | 58 + .../classes/Swift/Plugins/MessageLogger.php | 74 + .../Swift/Plugins/Pop/Pop3Connection.php | 31 + .../Swift/Plugins/Pop/Pop3Exception.php | 27 + .../Swift/Plugins/PopBeforeSmtpPlugin.php | 259 +++ .../Swift/Plugins/RedirectingPlugin.php | 213 ++ .../lib/classes/Swift/Plugins/Reporter.php | 32 + .../classes/Swift/Plugins/ReporterPlugin.php | 61 + .../Swift/Plugins/Reporters/HitReporter.php | 59 + .../Swift/Plugins/Reporters/HtmlReporter.php | 39 + .../lib/classes/Swift/Plugins/Sleeper.php | 24 + .../classes/Swift/Plugins/ThrottlerPlugin.php | 200 ++ .../lib/classes/Swift/Plugins/Timer.php | 24 + .../lib/classes/Swift/Preferences.php | 100 + .../Swift/ReplacementFilterFactory.php | 27 + .../classes/Swift/RfcComplianceException.php | 27 + .../lib/classes/Swift/SendmailTransport.php | 33 + .../swiftmailer/lib/classes/Swift/Signer.php | 20 + .../lib/classes/Swift/Signers/BodySigner.php | 33 + .../lib/classes/Swift/Signers/DKIMSigner.php | 686 +++++++ .../classes/Swift/Signers/DomainKeySigner.php | 512 +++++ .../classes/Swift/Signers/HeaderSigner.php | 65 + .../classes/Swift/Signers/OpenDKIMSigner.php | 185 ++ .../lib/classes/Swift/Signers/SMimeSigner.php | 417 ++++ .../lib/classes/Swift/SmtpTransport.php | 44 + .../swiftmailer/lib/classes/Swift/Spool.php | 53 + .../lib/classes/Swift/SpoolTransport.php | 35 + .../lib/classes/Swift/StreamFilter.php | 35 + .../ByteArrayReplacementFilter.php | 170 ++ .../StreamFilters/StringReplacementFilter.php | 70 + .../StringReplacementFilterFactory.php | 45 + .../lib/classes/Swift/SwiftException.php | 29 + .../lib/classes/Swift/Transport.php | 77 + .../Swift/Transport/AbstractSmtpTransport.php | 507 +++++ .../Esmtp/Auth/CramMd5Authenticator.php | 81 + .../Esmtp/Auth/LoginAuthenticator.php | 51 + .../Esmtp/Auth/NTLMAuthenticator.php | 692 +++++++ .../Esmtp/Auth/PlainAuthenticator.php | 50 + .../Esmtp/Auth/XOAuth2Authenticator.php | 70 + .../Swift/Transport/Esmtp/AuthHandler.php | 263 +++ .../Swift/Transport/Esmtp/Authenticator.php | 35 + .../classes/Swift/Transport/EsmtpHandler.php | 86 + .../Swift/Transport/EsmtpTransport.php | 407 ++++ .../Swift/Transport/FailoverTransport.php | 106 + .../lib/classes/Swift/Transport/IoBuffer.php | 67 + .../Swift/Transport/LoadBalancedTransport.php | 197 ++ .../classes/Swift/Transport/NullTransport.php | 101 + .../Swift/Transport/SendmailTransport.php | 161 ++ .../lib/classes/Swift/Transport/SmtpAgent.php | 36 + .../Swift/Transport/SpoolTransport.php | 125 ++ .../classes/Swift/Transport/StreamBuffer.php | 326 +++ .../lib/classes/Swift/TransportException.php | 29 + .../lib/dependency_maps/cache_deps.php | 23 + .../lib/dependency_maps/message_deps.php | 9 + .../lib/dependency_maps/mime_deps.php | 130 ++ .../lib/dependency_maps/transport_deps.php | 77 + .../swiftmailer/lib/mime_types.php | 1007 +++++++++ .../swiftmailer/lib/preferences.php | 19 + .../swiftmailer/lib/swift_required.php | 22 + .../lib/swiftmailer_generate_mimes_config.php | 193 ++ .../swiftmailer/swiftmailer/phpunit.xml.dist | 38 + .../tests/IdenticalBinaryConstraint.php | 62 + .../swiftmailer/tests/StreamCollector.php | 11 + .../tests/SwiftMailerSmokeTestCase.php | 46 + .../swiftmailer/tests/SwiftMailerTestCase.php | 38 + .../_samples/charsets/iso-2022-jp/one.txt | 11 + .../_samples/charsets/iso-8859-1/one.txt | 19 + .../tests/_samples/charsets/utf-8/one.txt | 22 + .../tests/_samples/charsets/utf-8/three.txt | 45 + .../tests/_samples/charsets/utf-8/two.txt | 3 + .../tests/_samples/dkim/dkim.test.priv | 15 + .../tests/_samples/dkim/dkim.test.pub | 6 + .../swiftmailer/tests/_samples/files/data.txt | 1 + .../tests/_samples/files/swiftmailer.png | Bin 0 -> 3194 bytes .../tests/_samples/files/textfile.zip | Bin 0 -> 202 bytes .../swiftmailer/tests/_samples/smime/CA.srl | 1 + .../swiftmailer/tests/_samples/smime/ca.crt | 21 + .../swiftmailer/tests/_samples/smime/ca.key | 27 + .../tests/_samples/smime/create-cert.sh | 40 + .../tests/_samples/smime/encrypt.crt | 19 + .../tests/_samples/smime/encrypt.key | 27 + .../tests/_samples/smime/encrypt2.crt | 19 + .../tests/_samples/smime/encrypt2.key | 27 + .../tests/_samples/smime/intermediate.crt | 19 + .../tests/_samples/smime/intermediate.key | 27 + .../swiftmailer/tests/_samples/smime/sign.crt | 19 + .../swiftmailer/tests/_samples/smime/sign.key | 27 + .../tests/_samples/smime/sign2.crt | 19 + .../tests/_samples/smime/sign2.key | 27 + .../tests/acceptance.conf.php.default | 37 + .../Swift/AttachmentAcceptanceTest.php | 12 + .../FileByteStreamAcceptanceTest.php | 162 ++ ...leCharacterReaderFactoryAcceptanceTest.php | 179 ++ .../DependencyContainerAcceptanceTest.php | 22 + .../Swift/EmbeddedFileAcceptanceTest.php | 12 + .../Encoder/Base64EncoderAcceptanceTest.php | 45 + .../Swift/Encoder/QpEncoderAcceptanceTest.php | 54 + .../Encoder/Rfc2231EncoderAcceptanceTest.php | 50 + .../KeyCache/ArrayKeyCacheAcceptanceTest.php | 173 ++ .../KeyCache/DiskKeyCacheAcceptanceTest.php | 173 ++ .../Swift/MessageAcceptanceTest.php | 55 + .../Swift/Mime/AttachmentAcceptanceTest.php | 126 ++ .../Base64ContentEncoderAcceptanceTest.php | 56 + .../NativeQpContentEncoderAcceptanceTest.php | 88 + .../PlainContentEncoderAcceptanceTest.php | 88 + .../QpContentEncoderAcceptanceTest.php | 160 ++ .../Swift/Mime/EmbeddedFileAcceptanceTest.php | 139 ++ .../Base64HeaderEncoderAcceptanceTest.php | 32 + .../Swift/Mime/MimePartAcceptanceTest.php | 130 ++ .../Mime/SimpleMessageAcceptanceTest.php | 1250 ++++++++++++ .../Swift/MimePartAcceptanceTest.php | 15 + .../AbstractStreamBufferAcceptanceTest.php | 131 ++ .../BasicSocketAcceptanceTest.php | 33 + .../StreamBuffer/ProcessAcceptanceTest.php | 26 + .../StreamBuffer/SocketTimeoutTest.php | 65 + .../StreamBuffer/SslSocketAcceptanceTest.php | 40 + .../StreamBuffer/TlsSocketAcceptanceTest.php | 39 + .../swiftmailer/tests/bootstrap.php | 21 + .../tests/bug/Swift/Bug111Test.php | 42 + .../tests/bug/Swift/Bug118Test.php | 20 + .../tests/bug/Swift/Bug206Test.php | 40 + .../tests/bug/Swift/Bug274Test.php | 25 + .../swiftmailer/tests/bug/Swift/Bug34Test.php | 75 + .../swiftmailer/tests/bug/Swift/Bug35Test.php | 73 + .../swiftmailer/tests/bug/Swift/Bug38Test.php | 192 ++ .../tests/bug/Swift/Bug518Test.php | 38 + .../swiftmailer/tests/bug/Swift/Bug51Test.php | 110 + .../tests/bug/Swift/Bug534Test.php | 38 + .../tests/bug/Swift/Bug650Test.php | 38 + .../swiftmailer/tests/bug/Swift/Bug71Test.php | 20 + .../swiftmailer/tests/bug/Swift/Bug76Test.php | 71 + ...FileByteStreamConsecutiveReadCallsTest.php | 18 + .../tests/fixtures/MimeEntityFixture.php | 67 + .../swiftmailer/tests/smoke.conf.php.default | 63 + .../smoke/Swift/Smoke/AttachmentSmokeTest.php | 33 + .../smoke/Swift/Smoke/BasicSmokeTest.php | 23 + .../Smoke/HtmlWithAttachmentSmokeTest.php | 31 + .../Swift/Smoke/InternationalSmokeTest.php | 40 + .../Swift/ByteStream/ArrayByteStreamTest.php | 202 ++ .../GenericFixedWidthReaderTest.php | 43 + .../CharacterReader/UsAsciiReaderTest.php | 52 + .../Swift/CharacterReader/Utf8ReaderTest.php | 65 + .../ArrayCharacterStreamTest.php | 358 ++++ .../unit/Swift/DependencyContainerTest.php | 176 ++ .../unit/Swift/Encoder/Base64EncoderTest.php | 173 ++ .../unit/Swift/Encoder/QpEncoderTest.php | 400 ++++ .../unit/Swift/Encoder/Rfc2231EncoderTest.php | 141 ++ .../unit/Swift/Events/CommandEventTest.php | 34 + .../unit/Swift/Events/EventObjectTest.php | 32 + .../unit/Swift/Events/ResponseEventTest.php | 38 + .../tests/unit/Swift/Events/SendEventTest.php | 96 + .../Events/SimpleEventDispatcherTest.php | 142 ++ .../Swift/Events/TransportChangeEventTest.php | 30 + .../Events/TransportExceptionEventTest.php | 41 + .../unit/Swift/KeyCache/ArrayKeyCacheTest.php | 240 +++ .../SimpleKeyCacheInputStreamTest.php | 73 + .../Mailer/ArrayRecipientIteratorTest.php | 42 + .../tests/unit/Swift/MailerTest.php | 145 ++ .../tests/unit/Swift/MessageTest.php | 133 ++ .../Swift/Mime/AbstractMimeEntityTest.php | 1092 ++++++++++ .../tests/unit/Swift/Mime/AttachmentTest.php | 321 +++ .../Base64ContentEncoderTest.php | 323 +++ .../PlainContentEncoderTest.php | 171 ++ .../ContentEncoder/QpContentEncoderTest.php | 516 +++++ .../unit/Swift/Mime/EmbeddedFileTest.php | 59 + .../HeaderEncoder/Base64HeaderEncoderTest.php | 13 + .../HeaderEncoder/QpHeaderEncoderTest.php | 221 ++ .../Swift/Mime/Headers/DateHeaderTest.php | 90 + .../Mime/Headers/IdentificationHeaderTest.php | 184 ++ .../Swift/Mime/Headers/MailboxHeaderTest.php | 329 +++ .../Mime/Headers/ParameterizedHeaderTest.php | 396 ++++ .../Swift/Mime/Headers/PathHeaderTest.php | 78 + .../Mime/Headers/UnstructuredHeaderTest.php | 353 ++++ .../tests/unit/Swift/Mime/IdGeneratorTest.php | 32 + .../tests/unit/Swift/Mime/MimePartTest.php | 234 +++ .../Swift/Mime/SimpleHeaderFactoryTest.php | 169 ++ .../unit/Swift/Mime/SimpleHeaderSetTest.php | 734 +++++++ .../unit/Swift/Mime/SimpleMessageTest.php | 837 ++++++++ .../unit/Swift/Mime/SimpleMimeEntityTest.php | 12 + .../Swift/Plugins/AntiFloodPluginTest.php | 93 + .../Plugins/BandwidthMonitorPluginTest.php | 128 ++ .../Swift/Plugins/DecoratorPluginTest.php | 284 +++ .../unit/Swift/Plugins/LoggerPluginTest.php | 188 ++ .../Swift/Plugins/Loggers/ArrayLoggerTest.php | 65 + .../Swift/Plugins/Loggers/EchoLoggerTest.php | 24 + .../Swift/Plugins/PopBeforeSmtpPluginTest.php | 101 + .../Swift/Plugins/RedirectingPluginTest.php | 183 ++ .../unit/Swift/Plugins/ReporterPluginTest.php | 86 + .../Plugins/Reporters/HitReporterTest.php | 64 + .../Plugins/Reporters/HtmlReporterTest.php | 54 + .../Swift/Plugins/ThrottlerPluginTest.php | 102 + .../unit/Swift/Signers/DKIMSignerTest.php | 220 ++ .../unit/Swift/Signers/OpenDKIMSignerTest.php | 45 + .../unit/Swift/Signers/SMimeSignerTest.php | 551 +++++ .../ByteArrayReplacementFilterTest.php | 129 ++ .../StringReplacementFilterFactoryTest.php | 36 + .../StringReplacementFilterTest.php | 59 + .../AbstractSmtpEventSupportTest.php | 558 +++++ .../unit/Swift/Transport/AbstractSmtpTest.php | 1316 ++++++++++++ .../Esmtp/Auth/CramMd5AuthenticatorTest.php | 64 + .../Esmtp/Auth/LoginAuthenticatorTest.php | 64 + .../Esmtp/Auth/NTLMAuthenticatorTest.php | 201 ++ .../Esmtp/Auth/PlainAuthenticatorTest.php | 67 + .../Swift/Transport/Esmtp/AuthHandlerTest.php | 165 ++ .../EsmtpTransport/ExtensionSupportTest.php | 561 +++++ .../Swift/Transport/EsmtpTransportTest.php | 298 +++ .../Swift/Transport/FailoverTransportTest.php | 600 ++++++ .../Transport/LoadBalancedTransportTest.php | 838 ++++++++ .../Swift/Transport/SendmailTransportTest.php | 150 ++ .../unit/Swift/Transport/StreamBufferTest.php | 43 + migrations/list.php | 1 + migrations/v20171126_200303_swift_mail.php | 26 + server.includes.inc.php | 2 + src/Classes/Email/EmailSender.php | 7 +- src/Classes/Email/PHPMailer.php | 17 +- src/Classes/Email/SMTPEmailSender.php | 6 +- src/Classes/Email/SNSEmailSender.php | 10 +- src/Classes/Email/SwiftMailer.php | 64 + src/Users/Admin/Api/UsersActionManager.php | 7 +- src/Users/Admin/Api/UsersEmailSender.php | 4 +- 418 files changed, 49835 insertions(+), 74 deletions(-) create mode 100644 lib/composer/vendor/doctrine/lexer/LICENSE create mode 100644 lib/composer/vendor/doctrine/lexer/README.md create mode 100644 lib/composer/vendor/doctrine/lexer/composer.json create mode 100644 lib/composer/vendor/doctrine/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/EmailLexer.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/EmailParser.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/EmailValidator.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/AtextAfterCFWS.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/CRLFAtTheEnd.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/CRLFX2.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/CRNoLF.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/CharNotAllowed.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/CommaInDomain.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/ConsecutiveAt.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/ConsecutiveDot.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/DomainHyphened.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/DotAtEnd.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/DotAtStart.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/ExpectingAT.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/ExpectingATEXT.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/ExpectingCTEXT.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/ExpectingDTEXT.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/ExpectingDomainLiteralClose.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/ExpectingQPair.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/InvalidEmail.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/NoDNSRecord.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/NoDomainPart.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/NoLocalPart.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/UnclosedComment.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/UnclosedQuotedString.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/UnopenedComment.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Parser/DomainPart.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Parser/LocalPart.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Parser/Parser.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/DNSCheckValidation.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/EmailValidation.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/Error/RFCWarnings.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/Error/SpoofEmail.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/Exception/EmptyValidationList.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/MultipleErrors.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/MultipleValidationWithAnd.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/NoRFCWarningsValidation.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/RFCValidation.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/SpoofCheckValidation.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/AddressLiteral.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/CFWSNearAt.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/CFWSWithFWS.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/Comment.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/DeprecatedComment.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/DomainLiteral.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/DomainTooLong.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/EmailTooLong.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6BadChar.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6ColonEnd.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6ColonStart.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6Deprecated.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6DoubleColon.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6GroupCount.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6MaxGroups.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/LabelTooLong.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/LocalTooLong.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/NoDNSMXRecord.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/ObsoleteDTEXT.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/QuotedPart.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/QuotedString.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/TLD.php create mode 100644 lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/Warning.php create mode 100644 lib/composer/vendor/egulias/email-validator/LICENSE create mode 100644 lib/composer/vendor/egulias/email-validator/README.md create mode 100644 lib/composer/vendor/egulias/email-validator/composer.json create mode 100644 lib/composer/vendor/egulias/email-validator/composer.lock create mode 100644 lib/composer/vendor/egulias/email-validator/phpunit.xml.dist create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/.gitattributes create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/.github/ISSUE_TEMPLATE.md create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/.gitignore create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/.php_cs.dist create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/.travis.yml create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/CHANGES create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/LICENSE create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/README create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/composer.json create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/doc/headers.rst create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/doc/index.rst create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/doc/introduction.rst create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/doc/japanese.rst create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/doc/messages.rst create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/doc/plugins.rst create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/doc/sending.rst create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Attachment.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory/SimpleCharacterReaderFactory.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/ArrayCharacterStream.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/EmbeddedFile.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Base64Encoder.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/Event.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/EventDispatcher.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/EventListener.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/EventObject.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendEvent.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SimpleEventDispatcher.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionEvent.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FailoverTransport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Filterable.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/IdGenerator.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Image.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/IoException.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/ArrayKeyCache.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/NullKeyCache.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/SimpleKeyCacheInputStream.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/Base64ContentEncoder.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Header.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/Base64HeaderEncoder.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/AbstractHeader.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/IdGenerator.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimePart.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderFactory.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/AntiFloodPlugin.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/DecoratorPlugin.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/LoggerPlugin.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Exception.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/PopBeforeSmtpPlugin.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ReporterPlugin.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ThrottlerPlugin.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Preferences.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/RfcComplianceException.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SendmailTransport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/ByteArrayReplacementFilter.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpHandler.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/LoadBalancedTransport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SmtpAgent.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SpoolTransport.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/dependency_maps/cache_deps.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/mime_types.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/preferences.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/lib/swift_required.php create mode 100755 lib/composer/vendor/swiftmailer/swiftmailer/lib/swiftmailer_generate_mimes_config.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/phpunit.xml.dist create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/IdenticalBinaryConstraint.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/StreamCollector.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/SwiftMailerSmokeTestCase.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/SwiftMailerTestCase.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/charsets/iso-2022-jp/one.txt create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/charsets/iso-8859-1/one.txt create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/charsets/utf-8/one.txt create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/charsets/utf-8/three.txt create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/charsets/utf-8/two.txt create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/dkim/dkim.test.priv create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/dkim/dkim.test.pub create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/files/data.txt create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/files/swiftmailer.png create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/files/textfile.zip create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/CA.srl create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/ca.crt create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/ca.key create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/create-cert.sh create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/encrypt.crt create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/encrypt.key create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/encrypt2.crt create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/encrypt2.key create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/intermediate.crt create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/intermediate.key create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/sign.crt create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/sign.key create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/sign2.crt create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/smime/sign2.key create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance.conf.php.default create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/AttachmentAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/ByteStream/FileByteStreamAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/CharacterReaderFactory/SimpleCharacterReaderFactoryAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/DependencyContainerAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/EmbeddedFileAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Encoder/Base64EncoderAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Encoder/QpEncoderAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Encoder/Rfc2231EncoderAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/KeyCache/ArrayKeyCacheAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/KeyCache/DiskKeyCacheAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/MessageAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/AttachmentAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/Base64ContentEncoderAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/NativeQpContentEncoderAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/PlainContentEncoderAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/QpContentEncoderAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/EmbeddedFileAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/HeaderEncoder/Base64HeaderEncoderAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/MimePartAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/SimpleMessageAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/MimePartAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/AbstractStreamBufferAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/BasicSocketAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/ProcessAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/SocketTimeoutTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/SslSocketAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/TlsSocketAcceptanceTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bootstrap.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug111Test.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug118Test.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug206Test.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug274Test.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug34Test.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug35Test.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug38Test.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug518Test.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug51Test.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug534Test.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug650Test.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug71Test.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug76Test.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/BugFileByteStreamConsecutiveReadCallsTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/fixtures/MimeEntityFixture.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke.conf.php.default create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke/Swift/Smoke/AttachmentSmokeTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke/Swift/Smoke/BasicSmokeTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke/Swift/Smoke/HtmlWithAttachmentSmokeTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke/Swift/Smoke/InternationalSmokeTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/ByteStream/ArrayByteStreamTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterReader/GenericFixedWidthReaderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterReader/UsAsciiReaderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterReader/Utf8ReaderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterStream/ArrayCharacterStreamTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/DependencyContainerTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Encoder/Base64EncoderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Encoder/QpEncoderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Encoder/Rfc2231EncoderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/CommandEventTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/EventObjectTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/ResponseEventTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/SendEventTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/SimpleEventDispatcherTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/TransportChangeEventTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/TransportExceptionEventTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/KeyCache/ArrayKeyCacheTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/KeyCache/SimpleKeyCacheInputStreamTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mailer/ArrayRecipientIteratorTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/MailerTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/MessageTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/AbstractMimeEntityTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/AttachmentTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/ContentEncoder/Base64ContentEncoderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/ContentEncoder/PlainContentEncoderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/ContentEncoder/QpContentEncoderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/EmbeddedFileTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/HeaderEncoder/Base64HeaderEncoderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/HeaderEncoder/QpHeaderEncoderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/DateHeaderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/IdentificationHeaderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/MailboxHeaderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/ParameterizedHeaderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/PathHeaderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/UnstructuredHeaderTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/IdGeneratorTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/MimePartTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleHeaderFactoryTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleHeaderSetTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleMessageTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleMimeEntityTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/AntiFloodPluginTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/BandwidthMonitorPluginTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/DecoratorPluginTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/LoggerPluginTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Loggers/ArrayLoggerTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Loggers/EchoLoggerTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/PopBeforeSmtpPluginTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/RedirectingPluginTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/ReporterPluginTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Reporters/HitReporterTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Reporters/HtmlReporterTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/ThrottlerPluginTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Signers/DKIMSignerTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Signers/OpenDKIMSignerTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Signers/SMimeSignerTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/StreamFilters/ByteArrayReplacementFilterTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/StreamFilters/StringReplacementFilterFactoryTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/StreamFilters/StringReplacementFilterTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/AbstractSmtpEventSupportTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/AbstractSmtpTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/CramMd5AuthenticatorTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/LoginAuthenticatorTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/NTLMAuthenticatorTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/PlainAuthenticatorTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/AuthHandlerTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/EsmtpTransport/ExtensionSupportTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/EsmtpTransportTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/FailoverTransportTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/LoadBalancedTransportTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/SendmailTransportTest.php create mode 100644 lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/StreamBufferTest.php create mode 100644 migrations/v20171126_200303_swift_mail.php create mode 100644 src/Classes/Email/SwiftMailer.php diff --git a/admin/users/lib.js b/admin/users/lib.js index 270d6c09..2ad720f8 100644 --- a/admin/users/lib.js +++ b/admin/users/lib.js @@ -55,7 +55,12 @@ UserAdapter.method('changePassword', function() { }); UserAdapter.method('saveUserSuccessCallBack', function(callBackData,serverData) { - this.showMessage("Create User","An email has been sent to "+callBackData['email']+" with a temporary password to login to IceHrm."); + var user = callBackData[0]; + if (callBackData[1]) { + this.showMessage("Create User","An email has been sent to "+user['email']+" with a temporary password to login to IceHrm."); + } else { + this.showMessage("Create User","User created successfully. But there was a problem sending welcome email."); + } this.get([]); }); @@ -76,7 +81,7 @@ UserAdapter.method('save', function() { var validator = new FormValidation(this.getTableName()+"_submit",true,{'ShowPopup':false,"LabelErrorClass":"error"}); if(validator.checkValues()){ var params = validator.getFormParameters(); - + var msg = this.doCustomValidation(params); if(msg == null){ var id = $('#'+this.getTableName()+"_submit #id").val(); @@ -84,63 +89,63 @@ UserAdapter.method('save', function() { $(params).attr('id',id); this.add(params,[]); }else{ - + var reqJson = JSON.stringify(params); - + var callBackData = []; callBackData['callBackData'] = []; callBackData['callBackSuccess'] = 'saveUserSuccessCallBack'; callBackData['callBackFail'] = 'saveUserFailCallBack'; - + this.customAction('saveUser','admin=users',reqJson,callBackData); } - + }else{ //$("#"+this.getTableName()+'Form .label').html(msg); //$("#"+this.getTableName()+'Form .label').show(); this.showMessage("Error Saving User",msg); } - - - + + + } }); UserAdapter.method('changePasswordConfirm', function() { $('#adminUsersChangePwd_error').hide(); - - var passwordValidation = function (str) { - var val = /^[a-zA-Z0-9]\w{6,}$/; - return str != null && val.test(str); + + var passwordValidation = function (str) { + var val = /^[a-zA-Z0-9]\w{6,}$/; + return str != null && val.test(str); }; - + var password = $('#adminUsersChangePwd #newpwd').val(); - + if(!passwordValidation(password)){ $('#adminUsersChangePwd_error').html("Password may contain only letters, numbers and should be longer than 6 characters"); $('#adminUsersChangePwd_error').show(); return; } - + var conPassword = $('#adminUsersChangePwd #conpwd').val(); - + if(conPassword != password){ $('#adminUsersChangePwd_error').html("Passwords don't match"); $('#adminUsersChangePwd_error').show(); return; } - + var req = {"id":this.currentId,"pwd":conPassword}; var reqJson = JSON.stringify(req); - + var callBackData = []; callBackData['callBackData'] = []; callBackData['callBackSuccess'] = 'changePasswordSuccessCallBack'; callBackData['callBackFail'] = 'changePasswordFailCallBack'; - + this.customAction('changePassword','admin=users',reqJson,callBackData); - + }); UserAdapter.method('closeChangePassword', function() { diff --git a/lib/composer/composer.json b/lib/composer/composer.json index 9ce74e66..c52a16d4 100644 --- a/lib/composer/composer.json +++ b/lib/composer/composer.json @@ -4,7 +4,8 @@ "twig/twig": "1.23.*", "gettext/gettext": "4.0.0", "consolidation/robo": "~1", - "filp/whoops": "~2.1" + "filp/whoops": "~2.1", + "swiftmailer/swiftmailer": "^6.0" }, "require-dev": { "phpunit/phpunit": "5.5.*" diff --git a/lib/composer/composer.lock b/lib/composer/composer.lock index 77337fe5..0e2f7e0a 100644 --- a/lib/composer/composer.lock +++ b/lib/composer/composer.lock @@ -1,10 +1,11 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "eb7486b98c829f999be2a3a5ce5d48b4", + "hash": "1944dee39b7f749b311e58061b00f233", + "content-hash": "7a06e9dbeabacf6aec7777ff8b9d4891", "packages": [ { "name": "consolidation/annotated-command", @@ -258,6 +259,117 @@ "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", "time": "2014-12-30 15:22:37" }, + { + "name": "doctrine/lexer", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ], + "time": "2014-09-09 13:34:57" + }, + { + "name": "egulias/email-validator", + "version": "2.1.3", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/1bec00a10039b823cc94eef4eddd47dcd3b2ca04", + "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^1.0.1", + "php": ">= 5.5" + }, + "require-dev": { + "dominicsayers/isemail": "dev-master", + "phpunit/phpunit": "^4.8.35", + "satooshi/php-coveralls": "^1.0.1" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "EmailValidator" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "time": "2017-11-15 23:40:40" + }, { "name": "filp/whoops", "version": "2.1.10", @@ -763,6 +875,61 @@ ], "time": "2016-10-10 12:19:37" }, + { + "name": "swiftmailer/swiftmailer", + "version": "v6.0.2", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "412333372fb6c8ffb65496a2bbd7321af75733fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/412333372fb6c8ffb65496a2bbd7321af75733fc", + "reference": "412333372fb6c8ffb65496a2bbd7321af75733fc", + "shasum": "" + }, + "require": { + "egulias/email-validator": "~2.0", + "php": ">=7.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.1", + "symfony/phpunit-bridge": "~3.3@dev" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + }, + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.symfony.com", + "keywords": [ + "email", + "mail", + "mailer" + ], + "time": "2017-09-30 22:39:41" + }, { "name": "symfony/console", "version": "v3.1.6", diff --git a/lib/composer/vendor/autoload.php b/lib/composer/vendor/autoload.php index 56583d02..382455cf 100644 --- a/lib/composer/vendor/autoload.php +++ b/lib/composer/vendor/autoload.php @@ -4,4 +4,4 @@ require_once __DIR__ . '/composer' . '/autoload_real.php'; -return ComposerAutoloaderInit17bd94f80a35033ddd449fc4168708d6::getLoader(); +return ComposerAutoloaderInita01cedac3fb3abb6b395843685a2b9da::getLoader(); diff --git a/lib/composer/vendor/composer/ClassLoader.php b/lib/composer/vendor/composer/ClassLoader.php index 5e1469e8..ff6ecfb8 100644 --- a/lib/composer/vendor/composer/ClassLoader.php +++ b/lib/composer/vendor/composer/ClassLoader.php @@ -13,9 +13,7 @@ namespace Composer\Autoload; /** - * ClassLoader implements a PSR-0 class loader - * - * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. * * $loader = new \Composer\Autoload\ClassLoader(); * @@ -39,6 +37,8 @@ namespace Composer\Autoload; * * @author Fabien Potencier * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ */ class ClassLoader { @@ -147,7 +147,7 @@ class ClassLoader * appending or prepending to the ones previously set for this namespace. * * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-0 base directories + * @param array|string $paths The PSR-4 base directories * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException diff --git a/lib/composer/vendor/composer/autoload_files.php b/lib/composer/vendor/composer/autoload_files.php index 79440721..548876d6 100644 --- a/lib/composer/vendor/composer/autoload_files.php +++ b/lib/composer/vendor/composer/autoload_files.php @@ -6,5 +6,6 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( - $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', + '2c102faa651ef8ea5874edb585946bce' => $vendorDir . '/swiftmailer/swiftmailer/lib/swift_required.php', ); diff --git a/lib/composer/vendor/composer/autoload_namespaces.php b/lib/composer/vendor/composer/autoload_namespaces.php index 3163d160..b85f909d 100644 --- a/lib/composer/vendor/composer/autoload_namespaces.php +++ b/lib/composer/vendor/composer/autoload_namespaces.php @@ -9,4 +9,5 @@ return array( 'Twig_' => array($vendorDir . '/twig/twig/lib'), 'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src'), 'PHPDocsMD' => array($vendorDir . '/victorjonsson/markdowndocs/src'), + 'Doctrine\\Common\\Lexer\\' => array($vendorDir . '/doctrine/lexer/lib'), ); diff --git a/lib/composer/vendor/composer/autoload_psr4.php b/lib/composer/vendor/composer/autoload_psr4.php index 826a51f4..bc642f37 100644 --- a/lib/composer/vendor/composer/autoload_psr4.php +++ b/lib/composer/vendor/composer/autoload_psr4.php @@ -24,6 +24,7 @@ return array( 'Interop\\Container\\' => array($vendorDir . '/container-interop/container-interop/src/Interop/Container'), 'Gettext\\Languages\\' => array($vendorDir . '/gettext/languages/src'), 'Gettext\\' => array($vendorDir . '/gettext/gettext/src'), + 'Egulias\\EmailValidator\\' => array($vendorDir . '/egulias/email-validator/EmailValidator'), 'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'), 'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'), 'Consolidation\\OutputFormatters\\' => array($vendorDir . '/consolidation/output-formatters/src'), diff --git a/lib/composer/vendor/composer/autoload_real.php b/lib/composer/vendor/composer/autoload_real.php index 8dc1908a..37c9bb7b 100644 --- a/lib/composer/vendor/composer/autoload_real.php +++ b/lib/composer/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit17bd94f80a35033ddd449fc4168708d6 +class ComposerAutoloaderInita01cedac3fb3abb6b395843685a2b9da { private static $loader; @@ -19,37 +19,52 @@ class ComposerAutoloaderInit17bd94f80a35033ddd449fc4168708d6 return self::$loader; } - spl_autoload_register(array('ComposerAutoloaderInit17bd94f80a35033ddd449fc4168708d6', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInita01cedac3fb3abb6b395843685a2b9da', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); - spl_autoload_unregister(array('ComposerAutoloaderInit17bd94f80a35033ddd449fc4168708d6', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInita01cedac3fb3abb6b395843685a2b9da', 'loadClassLoader')); - $map = require __DIR__ . '/autoload_namespaces.php'; - foreach ($map as $namespace => $path) { - $loader->set($namespace, $path); - } + $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION'); + if ($useStaticLoader) { + require_once __DIR__ . '/autoload_static.php'; - $map = require __DIR__ . '/autoload_psr4.php'; - foreach ($map as $namespace => $path) { - $loader->setPsr4($namespace, $path); - } + call_user_func(\Composer\Autoload\ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } - $classMap = require __DIR__ . '/autoload_classmap.php'; - if ($classMap) { - $loader->addClassMap($classMap); + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } } $loader->register(true); - $includeFiles = require __DIR__ . '/autoload_files.php'; - foreach ($includeFiles as $file) { - composerRequire17bd94f80a35033ddd449fc4168708d6($file); + if ($useStaticLoader) { + $includeFiles = Composer\Autoload\ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::$files; + } else { + $includeFiles = require __DIR__ . '/autoload_files.php'; + } + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequirea01cedac3fb3abb6b395843685a2b9da($fileIdentifier, $file); } return $loader; } } -function composerRequire17bd94f80a35033ddd449fc4168708d6($file) +function composerRequirea01cedac3fb3abb6b395843685a2b9da($fileIdentifier, $file) { - require $file; + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + require $file; + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + } } diff --git a/lib/composer/vendor/composer/autoload_static.php b/lib/composer/vendor/composer/autoload_static.php index ca1a40c9..2cee87c6 100644 --- a/lib/composer/vendor/composer/autoload_static.php +++ b/lib/composer/vendor/composer/autoload_static.php @@ -4,10 +4,11 @@ namespace Composer\Autoload; -class ComposerStaticInit91d733469d809ee1828b45ab2da48a10 +class ComposerStaticInita01cedac3fb3abb6b395843685a2b9da { public static $files = array ( '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', + '2c102faa651ef8ea5874edb585946bce' => __DIR__ . '/..' . '/swiftmailer/swiftmailer/lib/swift_required.php', ); public static $prefixLengthsPsr4 = array ( @@ -17,6 +18,7 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10 ), 'W' => array ( + 'Whoops\\' => 7, 'Webmozart\\Assert\\' => 17, ), 'S' => @@ -55,6 +57,10 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10 'Gettext\\Languages\\' => 18, 'Gettext\\' => 8, ), + 'E' => + array ( + 'Egulias\\EmailValidator\\' => 23, + ), 'D' => array ( 'Doctrine\\Instantiator\\' => 22, @@ -75,6 +81,10 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10 1 => __DIR__ . '/..' . '/phpdocumentor/type-resolver/src', 2 => __DIR__ . '/..' . '/phpdocumentor/reflection-docblock/src', ), + 'Whoops\\' => + array ( + 0 => __DIR__ . '/..' . '/filp/whoops/src/Whoops', + ), 'Webmozart\\Assert\\' => array ( 0 => __DIR__ . '/..' . '/webmozart/assert/src', @@ -139,6 +149,10 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10 array ( 0 => __DIR__ . '/..' . '/gettext/gettext/src', ), + 'Egulias\\EmailValidator\\' => + array ( + 0 => __DIR__ . '/..' . '/egulias/email-validator/EmailValidator', + ), 'Doctrine\\Instantiator\\' => array ( 0 => __DIR__ . '/..' . '/doctrine/instantiator/src/Doctrine/Instantiator', @@ -161,6 +175,10 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10 ), ); + public static $fallbackDirsPsr4 = array ( + 0 => __DIR__ . '/../..' . '/../../src', + ); + public static $prefixesPsr0 = array ( 'T' => array ( @@ -180,6 +198,13 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10 0 => __DIR__ . '/..' . '/victorjonsson/markdowndocs/src', ), ), + 'D' => + array ( + 'Doctrine\\Common\\Lexer\\' => + array ( + 0 => __DIR__ . '/..' . '/doctrine/lexer/lib', + ), + ), ); public static $classMap = array ( @@ -644,10 +669,11 @@ class ComposerStaticInit91d733469d809ee1828b45ab2da48a10 public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit91d733469d809ee1828b45ab2da48a10::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit91d733469d809ee1828b45ab2da48a10::$prefixDirsPsr4; - $loader->prefixesPsr0 = ComposerStaticInit91d733469d809ee1828b45ab2da48a10::$prefixesPsr0; - $loader->classMap = ComposerStaticInit91d733469d809ee1828b45ab2da48a10::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::$prefixDirsPsr4; + $loader->fallbackDirsPsr4 = ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::$fallbackDirsPsr4; + $loader->prefixesPsr0 = ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::$prefixesPsr0; + $loader->classMap = ComposerStaticInita01cedac3fb3abb6b395843685a2b9da::$classMap; }, null, ClassLoader::class); } diff --git a/lib/composer/vendor/composer/installed.json b/lib/composer/vendor/composer/installed.json index 6a6fd238..8c49f7a5 100644 --- a/lib/composer/vendor/composer/installed.json +++ b/lib/composer/vendor/composer/installed.json @@ -2490,5 +2490,177 @@ "whoops", "zf2" ] + }, + { + "name": "doctrine/lexer", + "version": "v1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "time": "2014-09-09 13:34:57", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ] + }, + { + "name": "egulias/email-validator", + "version": "2.1.3", + "version_normalized": "2.1.3.0", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/1bec00a10039b823cc94eef4eddd47dcd3b2ca04", + "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^1.0.1", + "php": ">= 5.5" + }, + "require-dev": { + "dominicsayers/isemail": "dev-master", + "phpunit/phpunit": "^4.8.35", + "satooshi/php-coveralls": "^1.0.1" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "time": "2017-11-15 23:40:40", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "EmailValidator" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ] + }, + { + "name": "swiftmailer/swiftmailer", + "version": "v6.0.2", + "version_normalized": "6.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "412333372fb6c8ffb65496a2bbd7321af75733fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/412333372fb6c8ffb65496a2bbd7321af75733fc", + "reference": "412333372fb6c8ffb65496a2bbd7321af75733fc", + "shasum": "" + }, + "require": { + "egulias/email-validator": "~2.0", + "php": ">=7.0.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.1", + "symfony/phpunit-bridge": "~3.3@dev" + }, + "time": "2017-09-30 22:39:41", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "http://swiftmailer.symfony.com", + "keywords": [ + "email", + "mail", + "mailer" + ] } ] diff --git a/lib/composer/vendor/doctrine/lexer/LICENSE b/lib/composer/vendor/doctrine/lexer/LICENSE new file mode 100644 index 00000000..5e781fce --- /dev/null +++ b/lib/composer/vendor/doctrine/lexer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2006-2013 Doctrine Project + +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/lib/composer/vendor/doctrine/lexer/README.md b/lib/composer/vendor/doctrine/lexer/README.md new file mode 100644 index 00000000..66f44308 --- /dev/null +++ b/lib/composer/vendor/doctrine/lexer/README.md @@ -0,0 +1,5 @@ +# Doctrine Lexer + +Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers. + +This lexer is used in Doctrine Annotations and in Doctrine ORM (DQL). diff --git a/lib/composer/vendor/doctrine/lexer/composer.json b/lib/composer/vendor/doctrine/lexer/composer.json new file mode 100644 index 00000000..8cd694c6 --- /dev/null +++ b/lib/composer/vendor/doctrine/lexer/composer.json @@ -0,0 +1,24 @@ +{ + "name": "doctrine/lexer", + "type": "library", + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "keywords": ["lexer", "parser"], + "homepage": "http://www.doctrine-project.org", + "license": "MIT", + "authors": [ + {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, + {"name": "Roman Borschel", "email": "roman@code-factory.org"}, + {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"} + ], + "require": { + "php": ">=5.3.2" + }, + "autoload": { + "psr-0": { "Doctrine\\Common\\Lexer\\": "lib/" } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/lib/composer/vendor/doctrine/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php b/lib/composer/vendor/doctrine/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php new file mode 100644 index 00000000..399a5523 --- /dev/null +++ b/lib/composer/vendor/doctrine/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php @@ -0,0 +1,327 @@ +. + */ + +namespace Doctrine\Common\Lexer; + +/** + * Base class for writing simple lexers, i.e. for creating small DSLs. + * + * @since 2.0 + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + */ +abstract class AbstractLexer +{ + /** + * Lexer original input string. + * + * @var string + */ + private $input; + + /** + * Array of scanned tokens. + * + * Each token is an associative array containing three items: + * - 'value' : the string value of the token in the input string + * - 'type' : the type of the token (identifier, numeric, string, input + * parameter, none) + * - 'position' : the position of the token in the input string + * + * @var array + */ + private $tokens = array(); + + /** + * Current lexer position in input string. + * + * @var integer + */ + private $position = 0; + + /** + * Current peek of current lexer position. + * + * @var integer + */ + private $peek = 0; + + /** + * The next token in the input. + * + * @var array + */ + public $lookahead; + + /** + * The last matched/seen token. + * + * @var array + */ + public $token; + + /** + * Sets the input data to be tokenized. + * + * The Lexer is immediately reset and the new input tokenized. + * Any unprocessed tokens from any previous input are lost. + * + * @param string $input The input to be tokenized. + * + * @return void + */ + public function setInput($input) + { + $this->input = $input; + $this->tokens = array(); + + $this->reset(); + $this->scan($input); + } + + /** + * Resets the lexer. + * + * @return void + */ + public function reset() + { + $this->lookahead = null; + $this->token = null; + $this->peek = 0; + $this->position = 0; + } + + /** + * Resets the peek pointer to 0. + * + * @return void + */ + public function resetPeek() + { + $this->peek = 0; + } + + /** + * Resets the lexer position on the input to the given position. + * + * @param integer $position Position to place the lexical scanner. + * + * @return void + */ + public function resetPosition($position = 0) + { + $this->position = $position; + } + + /** + * Retrieve the original lexer's input until a given position. + * + * @param integer $position + * + * @return string + */ + public function getInputUntilPosition($position) + { + return substr($this->input, 0, $position); + } + + /** + * Checks whether a given token matches the current lookahead. + * + * @param integer|string $token + * + * @return boolean + */ + public function isNextToken($token) + { + return null !== $this->lookahead && $this->lookahead['type'] === $token; + } + + /** + * Checks whether any of the given tokens matches the current lookahead. + * + * @param array $tokens + * + * @return boolean + */ + public function isNextTokenAny(array $tokens) + { + return null !== $this->lookahead && in_array($this->lookahead['type'], $tokens, true); + } + + /** + * Moves to the next token in the input string. + * + * @return boolean + */ + public function moveNext() + { + $this->peek = 0; + $this->token = $this->lookahead; + $this->lookahead = (isset($this->tokens[$this->position])) + ? $this->tokens[$this->position++] : null; + + return $this->lookahead !== null; + } + + /** + * Tells the lexer to skip input tokens until it sees a token with the given value. + * + * @param string $type The token type to skip until. + * + * @return void + */ + public function skipUntil($type) + { + while ($this->lookahead !== null && $this->lookahead['type'] !== $type) { + $this->moveNext(); + } + } + + /** + * Checks if given value is identical to the given token. + * + * @param mixed $value + * @param integer $token + * + * @return boolean + */ + public function isA($value, $token) + { + return $this->getType($value) === $token; + } + + /** + * Moves the lookahead token forward. + * + * @return array|null The next token or NULL if there are no more tokens ahead. + */ + public function peek() + { + if (isset($this->tokens[$this->position + $this->peek])) { + return $this->tokens[$this->position + $this->peek++]; + } else { + return null; + } + } + + /** + * Peeks at the next token, returns it and immediately resets the peek. + * + * @return array|null The next token or NULL if there are no more tokens ahead. + */ + public function glimpse() + { + $peek = $this->peek(); + $this->peek = 0; + return $peek; + } + + /** + * Scans the input string for tokens. + * + * @param string $input A query string. + * + * @return void + */ + protected function scan($input) + { + static $regex; + + if ( ! isset($regex)) { + $regex = sprintf( + '/(%s)|%s/%s', + implode(')|(', $this->getCatchablePatterns()), + implode('|', $this->getNonCatchablePatterns()), + $this->getModifiers() + ); + } + + $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE; + $matches = preg_split($regex, $input, -1, $flags); + + foreach ($matches as $match) { + // Must remain before 'value' assignment since it can change content + $type = $this->getType($match[0]); + + $this->tokens[] = array( + 'value' => $match[0], + 'type' => $type, + 'position' => $match[1], + ); + } + } + + /** + * Gets the literal for a given token. + * + * @param integer $token + * + * @return string + */ + public function getLiteral($token) + { + $className = get_class($this); + $reflClass = new \ReflectionClass($className); + $constants = $reflClass->getConstants(); + + foreach ($constants as $name => $value) { + if ($value === $token) { + return $className . '::' . $name; + } + } + + return $token; + } + + /** + * Regex modifiers + * + * @return string + */ + protected function getModifiers() + { + return 'i'; + } + + /** + * Lexical catchable patterns. + * + * @return array + */ + abstract protected function getCatchablePatterns(); + + /** + * Lexical non-catchable patterns. + * + * @return array + */ + abstract protected function getNonCatchablePatterns(); + + /** + * Retrieve token type. Also processes the token value if necessary. + * + * @param string $value + * + * @return integer + */ + abstract protected function getType(&$value); +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/EmailLexer.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/EmailLexer.php new file mode 100644 index 00000000..882c9681 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/EmailLexer.php @@ -0,0 +1,221 @@ + self::S_OPENPARENTHESIS, + ')' => self::S_CLOSEPARENTHESIS, + '<' => self::S_LOWERTHAN, + '>' => self::S_GREATERTHAN, + '[' => self::S_OPENBRACKET, + ']' => self::S_CLOSEBRACKET, + ':' => self::S_COLON, + ';' => self::S_SEMICOLON, + '@' => self::S_AT, + '\\' => self::S_BACKSLASH, + '/' => self::S_SLASH, + ',' => self::S_COMMA, + '.' => self::S_DOT, + '"' => self::S_DQUOTE, + '-' => self::S_HYPHEN, + '::' => self::S_DOUBLECOLON, + ' ' => self::S_SP, + "\t" => self::S_HTAB, + "\r" => self::S_CR, + "\n" => self::S_LF, + "\r\n" => self::CRLF, + 'IPv6' => self::S_IPV6TAG, + '{' => self::S_OPENQBRACKET, + '}' => self::S_CLOSEQBRACKET, + '' => self::S_EMPTY, + '\0' => self::C_NUL, + ); + + protected $hasInvalidTokens = false; + + protected $previous; + + public function reset() + { + $this->hasInvalidTokens = false; + parent::reset(); + } + + public function hasInvalidTokens() + { + return $this->hasInvalidTokens; + } + + /** + * @param $type + * @throws \UnexpectedValueException + * @return boolean + */ + public function find($type) + { + $search = clone $this; + $search->skipUntil($type); + + if (!$search->lookahead) { + throw new \UnexpectedValueException($type . ' not found'); + } + return true; + } + + /** + * getPrevious + * + * @return array token + */ + public function getPrevious() + { + return $this->previous; + } + + /** + * moveNext + * + * @return boolean + */ + public function moveNext() + { + $this->previous = $this->token; + + return parent::moveNext(); + } + + /** + * Lexical catchable patterns. + * + * @return string[] + */ + protected function getCatchablePatterns() + { + return array( + '[a-zA-Z_]+[46]?', //ASCII and domain literal + '[^\x00-\x7F]', //UTF-8 + '[0-9]+', + '\r\n', + '::', + '\s+?', + '.', + ); + } + + /** + * Lexical non-catchable patterns. + * + * @return string[] + */ + protected function getNonCatchablePatterns() + { + return array('[\xA0-\xff]+'); + } + + /** + * Retrieve token type. Also processes the token value if necessary. + * + * @param string $value + * @throws \InvalidArgumentException + * @return integer + */ + protected function getType(&$value) + { + if ($this->isNullType($value)) { + return self::C_NUL; + } + + if ($this->isValid($value)) { + return $this->charValue[$value]; + } + + if ($this->isUTF8Invalid($value)) { + $this->hasInvalidTokens = true; + return self::INVALID; + } + + return self::GENERIC; + } + + protected function isValid($value) + { + if (isset($this->charValue[$value])) { + return true; + } + + return false; + } + + /** + * @param $value + * @return bool + */ + protected function isNullType($value) + { + if ($value === "\0") { + return true; + } + + return false; + } + + /** + * @param $value + * @return bool + */ + protected function isUTF8Invalid($value) + { + if (preg_match('/\p{Cc}+/u', $value)) { + return true; + } + + return false; + } + + protected function getModifiers() + { + return 'iu'; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/EmailParser.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/EmailParser.php new file mode 100644 index 00000000..d0627d82 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/EmailParser.php @@ -0,0 +1,104 @@ + + */ +class EmailParser +{ + const EMAIL_MAX_LENGTH = 254; + + protected $warnings; + protected $domainPart = ''; + protected $localPart = ''; + protected $lexer; + protected $localPartParser; + protected $domainPartParser; + + public function __construct(EmailLexer $lexer) + { + $this->lexer = $lexer; + $this->localPartParser = new LocalPart($this->lexer); + $this->domainPartParser = new DomainPart($this->lexer); + $this->warnings = new \SplObjectStorage(); + } + + /** + * @param $str + * @return array + */ + public function parse($str) + { + $this->lexer->setInput($str); + + if (!$this->hasAtToken()) { + throw new NoLocalPart(); + } + + + $this->localPartParser->parse($str); + $this->domainPartParser->parse($str); + + $this->setParts($str); + + if ($this->lexer->hasInvalidTokens()) { + throw new ExpectingATEXT(); + } + + return array('local' => $this->localPart, 'domain' => $this->domainPart); + } + + public function getWarnings() + { + $localPartWarnings = $this->localPartParser->getWarnings(); + $domainPartWarnings = $this->domainPartParser->getWarnings(); + $this->warnings = array_merge($localPartWarnings, $domainPartWarnings); + + $this->addLongEmailWarning($this->localPart, $this->domainPart); + + return $this->warnings; + } + + public function getParsedDomainPart() + { + return $this->domainPart; + } + + protected function setParts($email) + { + $parts = explode('@', $email); + $this->domainPart = $this->domainPartParser->getDomainPart(); + $this->localPart = $parts[0]; + } + + protected function hasAtToken() + { + $this->lexer->moveNext(); + $this->lexer->moveNext(); + if ($this->lexer->token['type'] === EmailLexer::S_AT) { + return false; + } + + return true; + } + + /** + * @param string $localPart + * @param string $parsedDomainPart + */ + protected function addLongEmailWarning($localPart, $parsedDomainPart) + { + if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAIL_MAX_LENGTH) { + $this->warnings[EmailTooLong::CODE] = new EmailTooLong(); + } + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/EmailValidator.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/EmailValidator.php new file mode 100644 index 00000000..44b4b93c --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/EmailValidator.php @@ -0,0 +1,67 @@ +lexer = new EmailLexer(); + } + + /** + * @param $email + * @param EmailValidation $emailValidation + * @return bool + */ + public function isValid($email, EmailValidation $emailValidation) + { + $isValid = $emailValidation->isValid($email, $this->lexer); + $this->warnings = $emailValidation->getWarnings(); + $this->error = $emailValidation->getError(); + + return $isValid; + } + + /** + * @return boolean + */ + public function hasWarnings() + { + return !empty($this->warnings); + } + + /** + * @return array + */ + public function getWarnings() + { + return $this->warnings; + } + + /** + * @return InvalidEmail + */ + public function getError() + { + return $this->error; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/AtextAfterCFWS.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/AtextAfterCFWS.php new file mode 100644 index 00000000..97f41a2c --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Exception/AtextAfterCFWS.php @@ -0,0 +1,9 @@ +lexer->moveNext(); + + if ($this->lexer->token['type'] === EmailLexer::S_DOT) { + throw new DotAtStart(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_EMPTY) { + throw new NoDomainPart(); + } + if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) { + throw new DomainHyphened(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { + $this->warnings[DeprecatedComment::CODE] = new DeprecatedComment(); + $this->parseDomainComments(); + } + + $domain = $this->doParseDomainPart(); + + $prev = $this->lexer->getPrevious(); + $length = strlen($domain); + + if ($prev['type'] === EmailLexer::S_DOT) { + throw new DotAtEnd(); + } + if ($prev['type'] === EmailLexer::S_HYPHEN) { + throw new DomainHyphened(); + } + if ($length > self::DOMAIN_MAX_LENGTH) { + $this->warnings[DomainTooLong::CODE] = new DomainTooLong(); + } + if ($prev['type'] === EmailLexer::S_CR) { + throw new CRLFAtTheEnd(); + } + $this->domainPart = $domain; + } + + public function getDomainPart() + { + return $this->domainPart; + } + + public function checkIPV6Tag($addressLiteral, $maxGroups = 8) + { + $prev = $this->lexer->getPrevious(); + if ($prev['type'] === EmailLexer::S_COLON) { + $this->warnings[IPV6ColonEnd::CODE] = new IPV6ColonEnd(); + } + + $IPv6 = substr($addressLiteral, 5); + //Daniel Marschall's new IPv6 testing strategy + $matchesIP = explode(':', $IPv6); + $groupCount = count($matchesIP); + $colons = strpos($IPv6, '::'); + + if (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0) { + $this->warnings[IPV6BadChar::CODE] = new IPV6BadChar(); + } + + if ($colons === false) { + // We need exactly the right number of groups + if ($groupCount !== $maxGroups) { + $this->warnings[IPV6GroupCount::CODE] = new IPV6GroupCount(); + } + return; + } + + if ($colons !== strrpos($IPv6, '::')) { + $this->warnings[IPV6DoubleColon::CODE] = new IPV6DoubleColon(); + return; + } + + if ($colons === 0 || $colons === (strlen($IPv6) - 2)) { + // RFC 4291 allows :: at the start or end of an address + //with 7 other groups in addition + ++$maxGroups; + } + + if ($groupCount > $maxGroups) { + $this->warnings[IPV6MaxGroups::CODE] = new IPV6MaxGroups(); + } elseif ($groupCount === $maxGroups) { + $this->warnings[IPV6Deprecated::CODE] = new IPV6Deprecated(); + } + } + + protected function doParseDomainPart() + { + $domain = ''; + $openedParenthesis = 0; + do { + $prev = $this->lexer->getPrevious(); + + $this->checkNotAllowedChars($this->lexer->token); + + if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { + $this->parseComments(); + $openedParenthesis += $this->getOpenedParenthesis(); + $this->lexer->moveNext(); + $tmpPrev = $this->lexer->getPrevious(); + if ($tmpPrev['type'] === EmailLexer::S_CLOSEPARENTHESIS) { + $openedParenthesis--; + } + } + if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) { + if ($openedParenthesis === 0) { + throw new UnopenedComment(); + } else { + $openedParenthesis--; + } + } + + $this->checkConsecutiveDots(); + $this->checkDomainPartExceptions($prev); + + if ($this->hasBrackets()) { + $this->parseDomainLiteral(); + } + + $this->checkLabelLength($prev); + + if ($this->isFWS()) { + $this->parseFWS(); + } + + $domain .= $this->lexer->token['value']; + $this->lexer->moveNext(); + } while ($this->lexer->token); + + return $domain; + } + + private function checkNotAllowedChars($token) + { + $notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH=> true]; + if (isset($notAllowed[$token['type']])) { + throw new CharNotAllowed(); + } + } + + protected function parseDomainLiteral() + { + if ($this->lexer->isNextToken(EmailLexer::S_COLON)) { + $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart(); + } + if ($this->lexer->isNextToken(EmailLexer::S_IPV6TAG)) { + $lexer = clone $this->lexer; + $lexer->moveNext(); + if ($lexer->isNextToken(EmailLexer::S_DOUBLECOLON)) { + $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart(); + } + } + + return $this->doParseDomainLiteral(); + } + + protected function doParseDomainLiteral() + { + $IPv6TAG = false; + $addressLiteral = ''; + do { + if ($this->lexer->token['type'] === EmailLexer::C_NUL) { + throw new ExpectingDTEXT(); + } + + if ($this->lexer->token['type'] === EmailLexer::INVALID || + $this->lexer->token['type'] === EmailLexer::C_DEL || + $this->lexer->token['type'] === EmailLexer::S_LF + ) { + $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT(); + } + + if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENQBRACKET, EmailLexer::S_OPENBRACKET))) { + throw new ExpectingDTEXT(); + } + + if ($this->lexer->isNextTokenAny( + array(EmailLexer::S_HTAB, EmailLexer::S_SP, $this->lexer->token['type'] === EmailLexer::CRLF) + )) { + $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); + $this->parseFWS(); + } + + if ($this->lexer->isNextToken(EmailLexer::S_CR)) { + throw new CRNoLF(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH) { + $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT(); + $addressLiteral .= $this->lexer->token['value']; + $this->lexer->moveNext(); + $this->validateQuotedPair(); + } + if ($this->lexer->token['type'] === EmailLexer::S_IPV6TAG) { + $IPv6TAG = true; + } + if ($this->lexer->token['type'] === EmailLexer::S_CLOSEQBRACKET) { + break; + } + + $addressLiteral .= $this->lexer->token['value']; + + } while ($this->lexer->moveNext()); + + $addressLiteral = str_replace('[', '', $addressLiteral); + $addressLiteral = $this->checkIPV4Tag($addressLiteral); + + if (false === $addressLiteral) { + return $addressLiteral; + } + + if (!$IPv6TAG) { + $this->warnings[DomainLiteral::CODE] = new DomainLiteral(); + return $addressLiteral; + } + + $this->warnings[AddressLiteral::CODE] = new AddressLiteral(); + + $this->checkIPV6Tag($addressLiteral); + + return $addressLiteral; + } + + protected function checkIPV4Tag($addressLiteral) + { + $matchesIP = array(); + + // Extract IPv4 part from the end of the address-literal (if there is one) + if (preg_match( + '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/', + $addressLiteral, + $matchesIP + ) > 0 + ) { + $index = strrpos($addressLiteral, $matchesIP[0]); + if ($index === 0) { + $this->warnings[AddressLiteral::CODE] = new AddressLiteral(); + return false; + } + // Convert IPv4 part to IPv6 format for further testing + $addressLiteral = substr($addressLiteral, 0, $index) . '0:0'; + } + + return $addressLiteral; + } + + protected function checkDomainPartExceptions($prev) + { + $invalidDomainTokens = array( + EmailLexer::S_DQUOTE => true, + EmailLexer::S_SEMICOLON => true, + EmailLexer::S_GREATERTHAN => true, + EmailLexer::S_LOWERTHAN => true, + ); + + if (isset($invalidDomainTokens[$this->lexer->token['type']])) { + throw new ExpectingATEXT(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_COMMA) { + throw new CommaInDomain(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_AT) { + throw new ConsecutiveAt(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_OPENQBRACKET && $prev['type'] !== EmailLexer::S_AT) { + throw new ExpectingATEXT(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN && $this->lexer->isNextToken(EmailLexer::S_DOT)) { + throw new DomainHyphened(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH + && $this->lexer->isNextToken(EmailLexer::GENERIC)) { + throw new ExpectingATEXT(); + } + } + + protected function hasBrackets() + { + if ($this->lexer->token['type'] !== EmailLexer::S_OPENBRACKET) { + return false; + } + + try { + $this->lexer->find(EmailLexer::S_CLOSEBRACKET); + } catch (\RuntimeException $e) { + throw new ExpectingDomainLiteralClose(); + } + + return true; + } + + protected function checkLabelLength($prev) + { + if ($this->lexer->token['type'] === EmailLexer::S_DOT && + $prev['type'] === EmailLexer::GENERIC && + strlen($prev['value']) > 63 + ) { + $this->warnings[LabelTooLong::CODE] = new LabelTooLong(); + } + } + + protected function parseDomainComments() + { + $this->isUnclosedComment(); + while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) { + $this->warnEscaping(); + $this->lexer->moveNext(); + } + + $this->lexer->moveNext(); + if ($this->lexer->isNextToken(EmailLexer::S_DOT)) { + throw new ExpectingATEXT(); + } + } + + protected function addTLDWarnings() + { + if ($this->warnings[DomainLiteral::CODE]) { + $this->warnings[TLD::CODE] = new TLD(); + } + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Parser/LocalPart.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Parser/LocalPart.php new file mode 100644 index 00000000..8ab16ab4 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Parser/LocalPart.php @@ -0,0 +1,138 @@ +lexer->token['type'] !== EmailLexer::S_AT && $this->lexer->token) { + if ($this->lexer->token['type'] === EmailLexer::S_DOT && !$this->lexer->getPrevious()) { + throw new DotAtStart(); + } + + $closingQuote = $this->checkDQUOTE($closingQuote); + if ($closingQuote && $parseDQuote) { + $parseDQuote = $this->parseDoubleQuote(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) { + $this->parseComments(); + $openedParenthesis += $this->getOpenedParenthesis(); + } + if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) { + if ($openedParenthesis === 0) { + throw new UnopenedComment(); + } else { + $openedParenthesis--; + } + } + + $this->checkConsecutiveDots(); + + if ($this->lexer->token['type'] === EmailLexer::S_DOT && + $this->lexer->isNextToken(EmailLexer::S_AT) + ) { + throw new DotAtEnd(); + } + + $this->warnEscaping(); + $this->isInvalidToken($this->lexer->token, $closingQuote); + + if ($this->isFWS()) { + $this->parseFWS(); + } + + $this->lexer->moveNext(); + } + + $prev = $this->lexer->getPrevious(); + if (strlen($prev['value']) > LocalTooLong::LOCAL_PART_LENGTH) { + $this->warnings[LocalTooLong::CODE] = new LocalTooLong(); + } + } + + protected function parseDoubleQuote() + { + $parseAgain = true; + $special = array( + EmailLexer::S_CR => true, + EmailLexer::S_HTAB => true, + EmailLexer::S_LF => true + ); + + $invalid = array( + EmailLexer::C_NUL => true, + EmailLexer::S_HTAB => true, + EmailLexer::S_CR => true, + EmailLexer::S_LF => true + ); + $setSpecialsWarning = true; + + $this->lexer->moveNext(); + + while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && $this->lexer->token) { + $parseAgain = false; + if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) { + $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); + $setSpecialsWarning = false; + } + if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH && $this->lexer->isNextToken(EmailLexer::S_DQUOTE)) { + $this->lexer->moveNext(); + } + + $this->lexer->moveNext(); + + if (!$this->escaped() && isset($invalid[$this->lexer->token['type']])) { + throw new ExpectingATEXT(); + } + } + + $prev = $this->lexer->getPrevious(); + + if ($prev['type'] === EmailLexer::S_BACKSLASH) { + if (!$this->checkDQUOTE(false)) { + throw new UnclosedQuotedString(); + } + } + + if (!$this->lexer->isNextToken(EmailLexer::S_AT) && $prev['type'] !== EmailLexer::S_BACKSLASH) { + throw new ExpectingAT(); + } + + return $parseAgain; + } + + protected function isInvalidToken($token, $closingQuote) + { + $forbidden = array( + EmailLexer::S_COMMA, + EmailLexer::S_CLOSEBRACKET, + EmailLexer::S_OPENBRACKET, + EmailLexer::S_GREATERTHAN, + EmailLexer::S_LOWERTHAN, + EmailLexer::S_COLON, + EmailLexer::S_SEMICOLON, + EmailLexer::INVALID + ); + + if (in_array($token['type'], $forbidden) && !$closingQuote) { + throw new ExpectingATEXT(); + } + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Parser/Parser.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Parser/Parser.php new file mode 100644 index 00000000..e5042e1a --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Parser/Parser.php @@ -0,0 +1,215 @@ +lexer = $lexer; + } + + public function getWarnings() + { + return $this->warnings; + } + + abstract public function parse($str); + + /** @return int */ + public function getOpenedParenthesis() + { + return $this->openedParenthesis; + } + + /** + * validateQuotedPair + */ + protected function validateQuotedPair() + { + if (!($this->lexer->token['type'] === EmailLexer::INVALID + || $this->lexer->token['type'] === EmailLexer::C_DEL)) { + throw new ExpectedQPair(); + } + + $this->warnings[QuotedPart::CODE] = + new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']); + } + + protected function parseComments() + { + $this->openedParenthesis = 1; + $this->isUnclosedComment(); + $this->warnings[Comment::CODE] = new Comment(); + while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) { + if ($this->lexer->isNextToken(EmailLexer::S_OPENPARENTHESIS)) { + $this->openedParenthesis++; + } + $this->warnEscaping(); + $this->lexer->moveNext(); + } + + $this->lexer->moveNext(); + if ($this->lexer->isNextTokenAny(array(EmailLexer::GENERIC, EmailLexer::S_EMPTY))) { + throw new ExpectingATEXT(); + } + + if ($this->lexer->isNextToken(EmailLexer::S_AT)) { + $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); + } + } + + protected function isUnclosedComment() + { + try { + $this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS); + return true; + } catch (\RuntimeException $e) { + throw new UnclosedComment(); + } + } + + protected function parseFWS() + { + $previous = $this->lexer->getPrevious(); + + $this->checkCRLFInFWS(); + + if ($this->lexer->token['type'] === EmailLexer::S_CR) { + throw new CRNoLF(); + } + + if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] !== EmailLexer::S_AT) { + throw new AtextAfterCFWS(); + } + + if ($this->lexer->token['type'] === EmailLexer::S_LF || $this->lexer->token['type'] === EmailLexer::C_NUL) { + throw new ExpectingCTEXT(); + } + + if ($this->lexer->isNextToken(EmailLexer::S_AT) || $previous['type'] === EmailLexer::S_AT) { + $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt(); + } else { + $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS(); + } + } + + protected function checkConsecutiveDots() + { + if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) { + throw new ConsecutiveDot(); + } + } + + protected function isFWS() + { + if ($this->escaped()) { + return false; + } + + if ($this->lexer->token['type'] === EmailLexer::S_SP || + $this->lexer->token['type'] === EmailLexer::S_HTAB || + $this->lexer->token['type'] === EmailLexer::S_CR || + $this->lexer->token['type'] === EmailLexer::S_LF || + $this->lexer->token['type'] === EmailLexer::CRLF + ) { + return true; + } + + return false; + } + + protected function escaped() + { + $previous = $this->lexer->getPrevious(); + + if ($previous['type'] === EmailLexer::S_BACKSLASH + && + $this->lexer->token['type'] !== EmailLexer::GENERIC + ) { + return true; + } + + return false; + } + + protected function warnEscaping() + { + if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) { + return false; + } + + if ($this->lexer->isNextToken(EmailLexer::GENERIC)) { + throw new ExpectingATEXT(); + } + + if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) { + return false; + } + + $this->warnings[QuotedPart::CODE] = + new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']); + return true; + + } + + protected function checkDQUOTE($hasClosingQuote) + { + if ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE) { + return $hasClosingQuote; + } + if ($hasClosingQuote) { + return $hasClosingQuote; + } + $previous = $this->lexer->getPrevious(); + if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC) { + throw new ExpectingATEXT(); + } + + try { + $this->lexer->find(EmailLexer::S_DQUOTE); + $hasClosingQuote = true; + } catch (\Exception $e) { + throw new UnclosedQuotedString(); + } + $this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], $this->lexer->token['value']); + + return $hasClosingQuote; + } + + protected function checkCRLFInFWS() + { + if ($this->lexer->token['type'] !== EmailLexer::CRLF) { + return; + } + + if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) { + throw new CRLFX2(); + } + + if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) { + throw new CRLFAtTheEnd(); + } + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/DNSCheckValidation.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/DNSCheckValidation.php new file mode 100644 index 00000000..ecca1dd9 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/DNSCheckValidation.php @@ -0,0 +1,61 @@ +checkDNS($host); + } + + public function getError() + { + return $this->error; + } + + public function getWarnings() + { + return $this->warnings; + } + + protected function checkDNS($host) + { + $host = rtrim($host, '.') . '.'; + + $Aresult = true; + $MXresult = checkdnsrr($host, 'MX'); + + if (!$MXresult) { + $this->warnings[NoDNSMXRecord::CODE] = new NoDNSMXRecord(); + $Aresult = checkdnsrr($host, 'A') || checkdnsrr($host, 'AAAA'); + if (!$Aresult) { + $this->error = new NoDNSRecord(); + } + } + return $MXresult || $Aresult; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/EmailValidation.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/EmailValidation.php new file mode 100644 index 00000000..d5a015be --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/EmailValidation.php @@ -0,0 +1,34 @@ +errors = $errors; + parent::__construct(); + } + + public function getErrors() + { + return $this->errors; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/MultipleValidationWithAnd.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/MultipleValidationWithAnd.php new file mode 100644 index 00000000..43fa42a6 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/MultipleValidationWithAnd.php @@ -0,0 +1,110 @@ +validations = $validations; + $this->mode = $mode; + } + + /** + * {@inheritdoc} + */ + public function isValid($email, EmailLexer $emailLexer) + { + $result = true; + $errors = []; + foreach ($this->validations as $validation) { + $emailLexer->reset(); + $result = $result && $validation->isValid($email, $emailLexer); + $this->warnings = array_merge($this->warnings, $validation->getWarnings()); + $errors = $this->addNewError($validation->getError(), $errors); + + if ($this->shouldStop($result)) { + break; + } + } + + if (!empty($errors)) { + $this->error = new MultipleErrors($errors); + } + + return $result; + } + + private function addNewError($possibleError, array $errors) + { + if (null !== $possibleError) { + $errors[] = $possibleError; + } + + return $errors; + } + + private function shouldStop($result) + { + return !$result && $this->mode === self::STOP_ON_ERROR; + } + + /** + * {@inheritdoc} + */ + public function getError() + { + return $this->error; + } + + /** + * {@inheritdoc} + */ + public function getWarnings() + { + return $this->warnings; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/NoRFCWarningsValidation.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/NoRFCWarningsValidation.php new file mode 100644 index 00000000..e4bf0cc4 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/NoRFCWarningsValidation.php @@ -0,0 +1,41 @@ +getWarnings())) { + return true; + } + + $this->error = new RFCWarnings(); + + return false; + } + + /** + * {@inheritdoc} + */ + public function getError() + { + return $this->error ?: parent::getError(); + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/RFCValidation.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/RFCValidation.php new file mode 100644 index 00000000..c4ffe350 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/RFCValidation.php @@ -0,0 +1,49 @@ +parser = new EmailParser($emailLexer); + try { + $this->parser->parse((string)$email); + } catch (InvalidEmail $invalid) { + $this->error = $invalid; + return false; + } + + $this->warnings = $this->parser->getWarnings(); + return true; + } + + public function getError() + { + return $this->error; + } + + public function getWarnings() + { + return $this->warnings; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/SpoofCheckValidation.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/SpoofCheckValidation.php new file mode 100644 index 00000000..dd270556 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Validation/SpoofCheckValidation.php @@ -0,0 +1,45 @@ +setChecks(Spoofchecker::SINGLE_SCRIPT); + + if ($checker->isSuspicious($email)) { + $this->error = new SpoofEmail(); + } + + return $this->error === null; + } + + public function getError() + { + return $this->error; + } + + public function getWarnings() + { + return []; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/AddressLiteral.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/AddressLiteral.php new file mode 100644 index 00000000..77e70f7f --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/AddressLiteral.php @@ -0,0 +1,14 @@ +message = 'Address literal in domain part'; + $this->rfcNumber = 5321; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/CFWSNearAt.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/CFWSNearAt.php new file mode 100644 index 00000000..be43bbe6 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/CFWSNearAt.php @@ -0,0 +1,13 @@ +message = "Deprecated folding white space near @"; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/CFWSWithFWS.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/CFWSWithFWS.php new file mode 100644 index 00000000..dea3450e --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/CFWSWithFWS.php @@ -0,0 +1,13 @@ +message = 'Folding whites space followed by folding white space'; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/Comment.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/Comment.php new file mode 100644 index 00000000..704c2908 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/Comment.php @@ -0,0 +1,13 @@ +message = "Comments found in this email"; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/DeprecatedComment.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/DeprecatedComment.php new file mode 100644 index 00000000..ad43bd7c --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/DeprecatedComment.php @@ -0,0 +1,13 @@ +message = 'Deprecated comments'; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/DomainLiteral.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/DomainLiteral.php new file mode 100644 index 00000000..6f36b5e2 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/DomainLiteral.php @@ -0,0 +1,14 @@ +message = 'Domain Literal'; + $this->rfcNumber = 5322; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/DomainTooLong.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/DomainTooLong.php new file mode 100644 index 00000000..61ff17a7 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/DomainTooLong.php @@ -0,0 +1,14 @@ +message = 'Domain is too long, exceeds 255 chars'; + $this->rfcNumber = 5322; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/EmailTooLong.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/EmailTooLong.php new file mode 100644 index 00000000..497309db --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/EmailTooLong.php @@ -0,0 +1,15 @@ +message = 'Email is too long, exceeds ' . EmailParser::EMAIL_MAX_LENGTH; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6BadChar.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6BadChar.php new file mode 100644 index 00000000..ba2fcc01 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6BadChar.php @@ -0,0 +1,14 @@ +message = 'Bad char in IPV6 domain literal'; + $this->rfcNumber = 5322; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6ColonEnd.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6ColonEnd.php new file mode 100644 index 00000000..41afa78c --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6ColonEnd.php @@ -0,0 +1,14 @@ +message = ':: found at the end of the domain literal'; + $this->rfcNumber = 5322; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6ColonStart.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6ColonStart.php new file mode 100644 index 00000000..1bf754e3 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6ColonStart.php @@ -0,0 +1,14 @@ +message = ':: found at the start of the domain literal'; + $this->rfcNumber = 5322; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6Deprecated.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6Deprecated.php new file mode 100644 index 00000000..d752caaa --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6Deprecated.php @@ -0,0 +1,14 @@ +message = 'Deprecated form of IPV6'; + $this->rfcNumber = 5321; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6DoubleColon.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6DoubleColon.php new file mode 100644 index 00000000..4f823949 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6DoubleColon.php @@ -0,0 +1,14 @@ +message = 'Double colon found after IPV6 tag'; + $this->rfcNumber = 5322; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6GroupCount.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6GroupCount.php new file mode 100644 index 00000000..a59d317f --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6GroupCount.php @@ -0,0 +1,14 @@ +message = 'Group count is not IPV6 valid'; + $this->rfcNumber = 5322; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6MaxGroups.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6MaxGroups.php new file mode 100644 index 00000000..936274c1 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/IPV6MaxGroups.php @@ -0,0 +1,14 @@ +message = 'Reached the maximum number of IPV6 groups allowed'; + $this->rfcNumber = 5321; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/LabelTooLong.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/LabelTooLong.php new file mode 100644 index 00000000..daf07f40 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/LabelTooLong.php @@ -0,0 +1,14 @@ +message = 'Label too long'; + $this->rfcNumber = 5322; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/LocalTooLong.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/LocalTooLong.php new file mode 100644 index 00000000..0d08d8b3 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/LocalTooLong.php @@ -0,0 +1,15 @@ +message = 'Local part is too long, exceeds 64 chars (octets)'; + $this->rfcNumber = 5322; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/NoDNSMXRecord.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/NoDNSMXRecord.php new file mode 100644 index 00000000..b3c21a1f --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/NoDNSMXRecord.php @@ -0,0 +1,14 @@ +message = 'No MX DSN record was found for this email'; + $this->rfcNumber = 5321; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/ObsoleteDTEXT.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/ObsoleteDTEXT.php new file mode 100644 index 00000000..10f19e33 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/ObsoleteDTEXT.php @@ -0,0 +1,14 @@ +rfcNumber = 5322; + $this->message = 'Obsolete DTEXT in domain literal'; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/QuotedPart.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/QuotedPart.php new file mode 100644 index 00000000..7be9e6a3 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/QuotedPart.php @@ -0,0 +1,13 @@ +message = "Deprecated Quoted String found between $prevToken and $postToken"; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/QuotedString.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/QuotedString.php new file mode 100644 index 00000000..e9d56e1e --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/QuotedString.php @@ -0,0 +1,13 @@ +message = "Quoted String found between $prevToken and $postToken"; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/TLD.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/TLD.php new file mode 100644 index 00000000..2338b9f4 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/TLD.php @@ -0,0 +1,13 @@ +message = "RFC5321, TLD"; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/Warning.php b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/Warning.php new file mode 100644 index 00000000..ec6a365f --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/EmailValidator/Warning/Warning.php @@ -0,0 +1,30 @@ +message; + } + + public function code() + { + return self::CODE; + } + + public function RFCNumber() + { + return $this->rfcNumber; + } + + public function __toString() + { + return $this->message() . " rfc: " . $this->rfcNumber . "interal code: " . static::CODE; + } +} diff --git a/lib/composer/vendor/egulias/email-validator/LICENSE b/lib/composer/vendor/egulias/email-validator/LICENSE new file mode 100644 index 00000000..c34d2c19 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013-2016 Eduardo Gulias Davis + +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/lib/composer/vendor/egulias/email-validator/README.md b/lib/composer/vendor/egulias/email-validator/README.md new file mode 100644 index 00000000..fc7c89ea --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/README.md @@ -0,0 +1,79 @@ +# EmailValidator +[![Build Status](https://travis-ci.org/egulias/EmailValidator.png?branch=master)](https://travis-ci.org/egulias/EmailValidator) [![Coverage Status](https://coveralls.io/repos/egulias/EmailValidator/badge.png?branch=master)](https://coveralls.io/r/egulias/EmailValidator?branch=master) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/egulias/EmailValidator/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6/small.png)](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6) +============================= +With the help of [PHPStorm](https://www.jetbrains.com/phpstorm/) + +## Requirements ## + + * [Composer](https://getcomposer.org) is required for installation + * [Spoofchecking](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/SpoofCheckValidation.php) validation requires that your PHP system have the [PHP Internationalization Libraries](http://php.net/manual/en/book.intl.php) (also known as PHP Intl) + +## Installation ## + +Run the command below to install via Composer + +```shell +composer require egulias/email-validator "~2.1" +``` + +## Getting Started ## +`EmailValidator`requires you to decide which (or combination of them) validation/s strategy/ies you'd like to follow for each [validation](#available-validations). + +A basic example with the RFC validation +```php +isValid("example@example.com", new RFCValidation()); //true +``` + + +### Available validations ### + +1. [RFCValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/RFCValidation.php) +2. [NoRFCWarningsValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/NoRFCWarningsValidation.php) +3. [DNSCheckValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/DNSCheckValidation.php) +4. [SpoofCheckValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/SpoofCheckValidation.php) +5. [MultipleValidationWithAnd](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/MultipleValidationWithAnd.php) +6. [Your own validation](#how-to-extend) + +`MultipleValidationWithAnd` + +It is a validation that operates over other validations performing a logical and (&&) over the result of each validation. + +```php +isValid("example@example.com", $multipleValidations); //true +``` + +### How to extend ### + +It's easy! You just need to extend [EmailValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/EmailValidation.php) and you can use your own validation. + + +## Other Contributors ## +(You can find current contributors [here](https://github.com/egulias/EmailValidator/graphs/contributors)) + +As this is a port from another library and work, here are other people related to the previous one: + +* Ricard Clau [@ricardclau](http://github.com/ricardclau): Performance against PHP built-in filter_var +* Josepf Bielawski [@stloyd](http://github.com/stloyd): For its first re-work of Dominic's lib +* Dominic Sayers [@dominicsayers](http://github.com/dominicsayers): The original isemail function + +## License ## +Released under the MIT License attached with this code. + diff --git a/lib/composer/vendor/egulias/email-validator/composer.json b/lib/composer/vendor/egulias/email-validator/composer.json new file mode 100644 index 00000000..d09d785d --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/composer.json @@ -0,0 +1,39 @@ +{ + "name": "egulias/email-validator", + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "type": "Library", + "keywords": ["email", "validation", "validator", "emailvalidation", "emailvalidator"], + "license": "MIT", + "authors": [ + {"name": "Eduardo Gulias Davis"} + ], + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "repositories": [ + { + "type": "git", + "url": "https://github.com/dominicsayers/isemail" + } + ], + "require": { + "php": ">= 5.5", + "doctrine/lexer": "^1.0.1" + }, + "require-dev" : { + "satooshi/php-coveralls": "^1.0.1", + "phpunit/phpunit": "^4.8.35", + "dominicsayers/isemail": "dev-master" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "EmailValidator" + } + } +} diff --git a/lib/composer/vendor/egulias/email-validator/composer.lock b/lib/composer/vendor/egulias/email-validator/composer.lock new file mode 100644 index 00000000..93f5f69b --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/composer.lock @@ -0,0 +1,1813 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "d260b2d1d79771429aea640320702483", + "packages": [ + { + "name": "doctrine/lexer", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ], + "time": "2014-09-09T13:34:57+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14T21:17:01+00:00" + }, + { + "name": "dominicsayers/isemail", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/dominicsayers/isemail", + "reference": "64286085b40c39e6f39b1d23276d90635e5b3099" + }, + "type": "library", + "autoload": { + "files": [ + "is_email.php" + ] + }, + "license": [ + "BSD" + ], + "authors": [ + { + "name": "Dominic Sayers", + "email": "dominic@sayers.cc" + } + ], + "description": "Checks an email address against the following RFCs: 3696, 1123, 4291, 5321, 5322", + "homepage": "http://isemail.info", + "keywords": [ + "email", + "validation" + ], + "support": { + "source": "https://github.com/dominicsayers/isemail", + "issues": "https://github.com/dominicsayers/isemail/issues" + }, + "time": "2014-11-26T12:46:56+00:00" + }, + { + "name": "guzzle/guzzle", + "version": "v3.9.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle3.git", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9", + "reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.3.3", + "symfony/event-dispatcher": "~2.1" + }, + "replace": { + "guzzle/batch": "self.version", + "guzzle/cache": "self.version", + "guzzle/common": "self.version", + "guzzle/http": "self.version", + "guzzle/inflection": "self.version", + "guzzle/iterator": "self.version", + "guzzle/log": "self.version", + "guzzle/parser": "self.version", + "guzzle/plugin": "self.version", + "guzzle/plugin-async": "self.version", + "guzzle/plugin-backoff": "self.version", + "guzzle/plugin-cache": "self.version", + "guzzle/plugin-cookie": "self.version", + "guzzle/plugin-curlauth": "self.version", + "guzzle/plugin-error-response": "self.version", + "guzzle/plugin-history": "self.version", + "guzzle/plugin-log": "self.version", + "guzzle/plugin-md5": "self.version", + "guzzle/plugin-mock": "self.version", + "guzzle/plugin-oauth": "self.version", + "guzzle/service": "self.version", + "guzzle/stream": "self.version" + }, + "require-dev": { + "doctrine/cache": "~1.3", + "monolog/monolog": "~1.0", + "phpunit/phpunit": "3.7.*", + "psr/log": "~1.0", + "symfony/class-loader": "~2.1", + "zendframework/zend-cache": "2.*,<2.3", + "zendframework/zend-log": "2.*,<2.3" + }, + "suggest": { + "guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.9-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle": "src/", + "Guzzle\\Tests": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Guzzle Community", + "homepage": "https://github.com/guzzle/guzzle/contributors" + } + ], + "description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "abandoned": "guzzlehttp/guzzle", + "time": "2015-03-18T18:23:50+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "d094e337976dff9d8e2424e8485872194e768662" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d094e337976dff9d8e2424e8485872194e768662", + "reference": "d094e337976dff9d8e2424e8485872194e768662", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "~1.0", + "guzzlehttp/psr7": "~1.1", + "php": ">=5.5.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "~4.0", + "psr/log": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2016-03-21T20:02:09+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "bb9024c526b22f3fe6ae55a561fd70653d470aa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/bb9024c526b22f3fe6ae55a561fd70653d470aa8", + "reference": "bb9024c526b22f3fe6ae55a561fd70653d470aa8", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-03-08T01:15:46+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "31382fef2889136415751badebbd1cb022a4ed72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/31382fef2889136415751badebbd1cb022a4ed72", + "reference": "31382fef2889136415751badebbd1cb022a4ed72", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "PSR-7 message implementation", + "keywords": [ + "http", + "message", + "stream", + "uri" + ], + "time": "2016-04-13T19:56:01+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", + "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "dflydev/markdown": "~1.0", + "erusev/parsedown": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "phpDocumentor": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "mike.vanriel@naenius.com" + } + ], + "time": "2015-02-03T12:10:50+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972", + "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "~2.0", + "sebastian/comparator": "~1.1", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpspec/phpspec": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2016-02-15T07:46:21+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "^1.3.2", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-10-06T15:47:00+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2015-06-21T13:08:43+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4|~5" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2016-05-12T18:03:57+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-09-15T10:49:45+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "4.8.36", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "46023de9a91eec7dfb06cc56cb4e260017298517" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517", + "reference": "46023de9a91eec7dfb06cc56cb4e260017298517", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "~2.1", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.2.2", + "sebastian/diff": "~1.2", + "sebastian/environment": "~1.3", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.1|~3.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.8.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2017-06-21T08:07:12+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2015-10-02T06:51:40+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2015-05-04T20:22:00+00:00" + }, + { + "name": "psr/log", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", + "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-0": { + "Psr\\Log\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2012-12-21T11:40:51+00:00" + }, + { + "name": "satooshi/php-coveralls", + "version": "v1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-coveralls/php-coveralls.git", + "reference": "9c07b63acbc9709344948b6fd4f63a32b2ef4127" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-coveralls/php-coveralls/zipball/9c07b63acbc9709344948b6fd4f63a32b2ef4127", + "reference": "9c07b63acbc9709344948b6fd4f63a32b2ef4127", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-simplexml": "*", + "guzzle/guzzle": "^2.8 || ^3.0", + "php": "^5.3.3 || ^7.0", + "psr/log": "^1.0", + "symfony/config": "^2.1 || ^3.0 || ^4.0", + "symfony/console": "^2.1 || ^3.0 || ^4.0", + "symfony/stopwatch": "^2.0 || ^3.0 || ^4.0", + "symfony/yaml": "^2.0 || ^3.0 || ^4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.4.3 || ^6.0" + }, + "suggest": { + "symfony/http-kernel": "Allows Symfony integration" + }, + "bin": [ + "bin/coveralls" + ], + "type": "library", + "autoload": { + "psr-4": { + "Satooshi\\": "src/Satooshi/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kitamura Satoshi", + "email": "with.no.parachute@gmail.com", + "homepage": "https://www.facebook.com/satooshi.jp" + } + ], + "description": "PHP client library for Coveralls API", + "homepage": "https://github.com/php-coveralls/php-coveralls", + "keywords": [ + "ci", + "coverage", + "github", + "test" + ], + "time": "2017-10-14T23:15:34+00:00" + }, + { + "name": "sebastian/comparator", + "version": "1.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2 || ~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2017-01-29T09:50:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-12-08T07:14:41+00:00" + }, + { + "name": "sebastian/environment", + "version": "1.3.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "2292b116f43c272ff4328083096114f84ea46a56" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/2292b116f43c272ff4328083096114f84ea46a56", + "reference": "2292b116f43c272ff4328083096114f84ea46a56", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-05-04T07:59:13+00:00" + }, + { + "name": "sebastian/exporter", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "7ae5513327cb536431847bcc0c10edba2701064e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e", + "reference": "7ae5513327cb536431847bcc0c10edba2701064e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2015-06-21T07:55:53+00:00" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12T03:26:01+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-11-11T19:50:13+00:00" + }, + { + "name": "sebastian/version", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2015-06-21T13:59:46+00:00" + }, + { + "name": "symfony/config", + "version": "v3.0.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "24f155da1ff180df8e15e34a8f6e2f8a0eadefa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/24f155da1ff180df8e15e34a8f6e2f8a0eadefa8", + "reference": "24f155da1ff180df8e15e34a8f6e2f8a0eadefa8", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/filesystem": "~2.8|~3.0" + }, + "suggest": { + "symfony/yaml": "To use the yaml reference dumper" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Config Component", + "homepage": "https://symfony.com", + "time": "2016-04-20T18:53:54+00:00" + }, + { + "name": "symfony/console", + "version": "v3.0.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "34a214710e0714b6efcf40ba3cd1e31373a97820" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/34a214710e0714b6efcf40ba3cd1e31373a97820", + "reference": "34a214710e0714b6efcf40ba3cd1e31373a97820", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2016-04-28T09:48:42+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v2.8.30", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "b59aacf238fadda50d612c9de73b74751872a903" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b59aacf238fadda50d612c9de73b74751872a903", + "reference": "b59aacf238fadda50d612c9de73b74751872a903", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "^2.0.5|~3.0.0", + "symfony/dependency-injection": "~2.6|~3.0.0", + "symfony/expression-language": "~2.6|~3.0.0", + "symfony/stopwatch": "~2.3|~3.0.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2017-11-05T15:25:56+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v3.0.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "74fec3511b62cb934b64bce1d96f06fffa4beafd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/74fec3511b62cb934b64bce1d96f06fffa4beafd", + "reference": "74fec3511b62cb934b64bce1d96f06fffa4beafd", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Filesystem Component", + "homepage": "https://symfony.com", + "time": "2016-04-12T18:09:53+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "1289d16209491b584839022f29257ad859b8532d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d", + "reference": "1289d16209491b584839022f29257ad859b8532d", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2016-01-20T09:13:37+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v3.0.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "6015187088421e9499d8f8316bdb396f8b806c06" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/6015187088421e9499d8f8316bdb396f8b806c06", + "reference": "6015187088421e9499d8f8316bdb396f8b806c06", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Stopwatch Component", + "homepage": "https://symfony.com", + "time": "2016-03-04T07:55:57+00:00" + }, + { + "name": "symfony/yaml", + "version": "v3.0.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "0047c8366744a16de7516622c5b7355336afae96" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/0047c8366744a16de7516622c5b7355336afae96", + "reference": "0047c8366744a16de7516622c5b7355336afae96", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2016-03-04T07:55:57+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": { + "dominicsayers/isemail": 20 + }, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">= 5.5" + }, + "platform-dev": [] +} diff --git a/lib/composer/vendor/egulias/email-validator/phpunit.xml.dist b/lib/composer/vendor/egulias/email-validator/phpunit.xml.dist new file mode 100644 index 00000000..b0812f97 --- /dev/null +++ b/lib/composer/vendor/egulias/email-validator/phpunit.xml.dist @@ -0,0 +1,26 @@ + + + + + + ./Tests/EmailValidator + ./vendor/ + + + + + + ./vendor + + + diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/.gitattributes b/lib/composer/vendor/swiftmailer/swiftmailer/.gitattributes new file mode 100644 index 00000000..09c3fba9 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/.gitattributes @@ -0,0 +1,9 @@ +*.crt -crlf +*.key -crlf +*.srl -crlf +*.pub -crlf +*.priv -crlf +*.txt -crlf + +# ignore /notes in the git-generated distributed .zip archive +/doc/notes export-ignore diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/.github/ISSUE_TEMPLATE.md b/lib/composer/vendor/swiftmailer/swiftmailer/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..5db65246 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,19 @@ + + +| Q | A +| ------------------- | ----- +| Bug report? | yes/no +| Feature request? | yes/no +| RFC? | yes/no +| How used? | Standalone/Symfony/3party +| Swiftmailer version | x.y.z +| PHP version | x.y.z + +### Observed behaviour + + +### Expected behaviour + + +### Example + diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/.github/PULL_REQUEST_TEMPLATE.md b/lib/composer/vendor/swiftmailer/swiftmailer/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..4b395107 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,14 @@ + + +| Q | A +| ------------- | --- +| Bug fix? | yes/no +| New feature? | yes/no +| Doc update? | yes/no +| BC breaks? | yes/no +| Deprecations? | yes/no +| Fixed tickets | #... +| License | MIT + + + diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/.gitignore b/lib/composer/vendor/swiftmailer/swiftmailer/.gitignore new file mode 100644 index 00000000..20d389a1 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/.gitignore @@ -0,0 +1,8 @@ +/.php_cs.cache +/.phpunit +/build/* +/composer.lock +/phpunit.xml +/tests/acceptance.conf.php +/tests/smoke.conf.php +/vendor/ diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/.php_cs.dist b/lib/composer/vendor/swiftmailer/swiftmailer/.php_cs.dist new file mode 100644 index 00000000..f18d65d4 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/.php_cs.dist @@ -0,0 +1,15 @@ +setRules(array( + '@Symfony' => true, + '@Symfony:risky' => true, + 'array_syntax' => array('syntax' => 'long'), + 'no_unreachable_default_argument_value' => false, + 'braces' => array('allow_single_line_closure' => true), + 'heredoc_to_nowdoc' => false, + 'phpdoc_annotation_without_dot' => false, + )) + ->setRiskyAllowed(true) + ->setFinder(PhpCsFixer\Finder::create()->in(__DIR__)) +; diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/.travis.yml b/lib/composer/vendor/swiftmailer/swiftmailer/.travis.yml new file mode 100644 index 00000000..60b25413 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/.travis.yml @@ -0,0 +1,24 @@ +language: php + +sudo: false + +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 mime-types -v 2.99.1 + - gem install mailcatcher + - mailcatcher --smtp-port 4456 + +script: SYMFONY_PHPUNIT_VERSION=6.1 ./vendor/bin/simple-phpunit + +matrix: + include: + - php: 7.0 + - php: 7.1 + fast_finish: true + +cache: + directories: + - .phpunit diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/CHANGES b/lib/composer/vendor/swiftmailer/swiftmailer/CHANGES new file mode 100644 index 00000000..8ded49f8 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/CHANGES @@ -0,0 +1,299 @@ +Changelog +========= + +6.0.2 (2017-09-30) +------------------ + + * fixed DecoratorPlugin + * removed usage of getmypid() + +6.0.1 (2017-05-20) +------------------ + + * fixed BC break that can be avoided easily + +6.0.0 (2017-05-19) +------------------ + + * added Swift_Transport::ping() + * removed Swift_Mime_HeaderFactory, Swift_Mime_HeaderSet, Swift_Mime_Message, Swift_Mime_MimeEntity, + and Swift_Mime_ParameterizedHeader interfaces + * removed Swift_MailTransport and Swift_Transport_MailTransport + * removed Swift_Encoding + * removed the Swift_Transport_MailInvoker interface and Swift_Transport_SimpleMailInvoker class + * removed the Swift_SignedMessage class + * removed newInstance() methods everywhere + * methods operating on Date header now use DateTimeImmutable object instead of Unix timestamp; + Swift_Mime_Headers_DateHeader::getTimestamp()/setTimestamp() renamed to getDateTime()/setDateTime() + * bumped minimum version to PHP 7.0 + * removed Swift_Validate and replaced by egulias/email-validator + +5.4.9 (2017-XX-XX) +------------------ + + * n/a + +5.4.8 (2017-05-01) +------------------ + + * fixed encoding inheritance in addPart() + * fixed sorting MIME children when their types are equal + +5.4.7 (2017-04-20) +------------------ + + * fixed NTLMAuthenticator clobbering bcmath scale + +5.4.6 (2017-02-13) +------------------ + + * removed exceptions thrown in destructors as they lead to fatal errors + * switched to use sha256 by default in DKIM as per the RFC + * fixed an 'Undefined variable: pipes' PHP notice + * fixed long To headers when using the mail transport + * fixed NTLMAuthenticator when no domain is passed with the username + * prevented fatal error during unserialization of a message + * fixed a PHP warning when sending a message that has a length of a multiple of 8192 + +5.4.5 (2016-12-29) +------------------ + + * SECURITY FIX: fixed CVE-2016-10074 by disallowing potentially unsafe shell characters + + Prior to 5.4.5, the mail transport (Swift_Transport_MailTransport) was vulnerable to passing + arbitrary shell arguments if the "From", "ReturnPath" or "Sender" header came + from a non-trusted source, potentially allowing Remote Code Execution + * deprecated the mail transport + +5.4.4 (2016-11-23) +------------------ + + * reverted escaping command-line args to mail (PHP mail() function already does it) + +5.4.3 (2016-07-08) +------------------ + + * fixed SimpleHeaderSet::has()/get() when the 0 index is removed + * removed the need to have mcrypt installed + * fixed broken MIME header encoding with quotes/colons and non-ascii chars + * allowed mail transport send for messages without To header + * fixed PHP 7 support + +5.4.2 (2016-05-01) +------------------ + + * fixed support for IPv6 sockets + * added auto-retry when sending messages from the memory spool + * fixed consecutive read calls in Swift_ByteStream_FileByteStream + * added support for iso-8859-15 encoding + * fixed PHP mail extra params on missing reversePath + * added methods to set custom stream context options + * fixed charset changes in QpContentEncoderProxy + * added return-path header to the ignoredHeaders list of DKIMSigner + * fixed crlf for subject using mail + * fixed add soft line break only when necessary + * fixed escaping command-line args to mail + +5.4.1 (2015-06-06) +------------------ + + * made Swiftmailer exceptions confirm to PHP base exception constructor signature + * fixed MAIL FROM & RCPT TO headers to be RFC compliant + +5.4.0 (2015-03-14) +------------------ + + * added the possibility to add extra certs to PKCS#7 signature + * fix base64 encoding with streams + * added a new RESULT_SPOOLED status for SpoolTransport + * fixed getBody() on attachments when called more than once + * removed dots from generated filenames in filespool + +5.3.1 (2014-12-05) +------------------ + + * fixed cloning of messages with attachments + +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/lib/composer/vendor/swiftmailer/swiftmailer/LICENSE b/lib/composer/vendor/swiftmailer/swiftmailer/LICENSE new file mode 100644 index 00000000..485f1d6d --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013-2016 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/lib/composer/vendor/swiftmailer/swiftmailer/README b/lib/composer/vendor/swiftmailer/swiftmailer/README new file mode 100644 index 00000000..a41b6602 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/README @@ -0,0 +1,15 @@ +Swift Mailer +------------ + +Swift Mailer is a component based mailing solution for PHP 7. +It is released under the MIT license. + +Homepage: https://swiftmailer.symfony.com/ +Documentation: https://swiftmailer.symfony.com/docs/introduction.html +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/lib/composer/vendor/swiftmailer/swiftmailer/composer.json b/lib/composer/vendor/swiftmailer/swiftmailer/composer.json new file mode 100644 index 00000000..40439830 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/composer.json @@ -0,0 +1,36 @@ +{ + "name": "swiftmailer/swiftmailer", + "type": "library", + "description": "Swiftmailer, free feature-rich PHP mailer", + "keywords": ["mail","mailer","email"], + "homepage": "http://swiftmailer.symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "require": { + "php": ">=7.0.0", + "egulias/email-validator": "~2.0" + }, + "require-dev": { + "mockery/mockery": "~0.9.1", + "symfony/phpunit-bridge": "~3.3@dev" + }, + "autoload": { + "files": ["lib/swift_required.php"] + }, + "autoload-dev": { + "psr-0": { "Swift_": "tests/unit" } + }, + "extra": { + "branch-alias": { + "dev-master": "6.0-dev" + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/doc/headers.rst b/lib/composer/vendor/swiftmailer/swiftmailer/doc/headers.rst new file mode 100644 index 00000000..4f398c82 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/doc/headers.rst @@ -0,0 +1,609 @@ +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_SimpleMimeEntity``. 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:: + + $message = new Swift_Message(); + + // 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:: + + 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:: + + 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``:: + + 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:: + + $message = new Swift_Message(); + $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:: + + $subject = $message->getHeaders()->get('Subject'); + $subject->setValue('new subject'); + +When output via ``toString()``, a text header produces something like the +following:: + + $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:: + + $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:: + + $message = new Swift_Message(); + $headers = $message->getHeaders(); + $headers->addParameterizedHeader( + 'Header-Name', 'header value', + ['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):: + + $type = $message->getHeaders()->get('Content-Type'); + + // setParameters() takes an associative array + $type->setParameters([ + '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:: + + $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:: + + $attachment = new Swift_Attachment(); + $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 as a DateTimeImmutable object. The +object is used to create a correctly structured RFC 2822 formatted date with +timezone 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:: + + $message = new Swift_Message(); + $headers = $message->getHeaders(); + $headers->addDateHeader('Your-Header', new DateTimeImmutable('3 days ago')); + +Changing the value of an existing date header is done by calling it's +``setDateTime()`` method:: + + $date = $message->getHeaders()->get('Date'); + $date->setDateTime(new DateTimeImmutable()); + +When output via ``toString()``, a date header produces something like the +following:: + + $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:: + + $message = new Swift_Message(); + $headers = $message->getHeaders(); + $headers->addMailboxHeader('Your-Header-Name', [ + '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:: + + $to = $message->getHeaders()->get('To'); + $to->setNameAddresses([ + '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:: + + $to = $message->getHeaders()->get('To'); + $to->setAddresses([ + '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()``:: + + $to = $message->getHeaders()->get('To'); + $to->setAddresses('joe-bloggs@example.org'); + +When output via ``toString()``, a mailbox header produces something like the +following:: + + $to = $message->getHeaders()->get('To'); + $to->setNameAddresses([ + '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:: + + $message = new Swift_Message(); + $headers = $message->getHeaders(); + $headers->addIdHeader('Your-Header-Name', '123456.unqiue@example.org'); + +Changing the value of an existing ID header is done by calling its ``setId()`` +method:: + + $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:: + + $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:: + + $message = new Swift_Message(); + $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:: + + $return = $message->getHeaders()->get('Return-Path'); + $return->setAddress('my-address@example.org'); + +When output via ``toString()``, a path header produces something like the +following:: + + $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. + +The added header will appear in the message when it is sent:: + + // Adding a custom header to a message + $message = new Swift_Message(); + $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:: + + $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(); + +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. + +Check if a Header Exists +~~~~~~~~~~~~~~~~~~~~~~~~ + +You can check if a named header is present in a HeaderSet by calling its +``has()`` method:: + + $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'; + } + +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. + +Removing Headers +~~~~~~~~~~~~~~~~ + +Removing a Header from the HeaderSet is done by calling the HeaderSet's +``remove()`` or ``removeAll()`` methods:: + + $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); + +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. + +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:: + +The header will be updated inside the HeaderSet and the changes will be seen +when the message is sent:: + + $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([ + 'person@example.org' => 'Person', + 'thing@example.org' + ]); + + // Using the setFieldBodyModel() just delegates to the correct method + // So here to calls setNameAddresses() + $to->setFieldBodyModel([ + 'person@example.org' => 'Person', + 'thing@example.org' + ]); diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/doc/index.rst b/lib/composer/vendor/swiftmailer/swiftmailer/doc/index.rst new file mode 100644 index 00000000..5d928891 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/doc/index.rst @@ -0,0 +1,12 @@ +Swiftmailer +=========== + +.. toctree:: + :maxdepth: 2 + + introduction + messages + headers + sending + plugins + japanese diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/doc/introduction.rst b/lib/composer/vendor/swiftmailer/swiftmailer/doc/introduction.rst new file mode 100644 index 00000000..774e9f46 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/doc/introduction.rst @@ -0,0 +1,61 @@ +Introduction +============ + +Swift Mailer is a for sending e-mails from PHP applications. + +System Requirements +------------------- + +Swift Mailer requires PHP 7.0 or higher (``proc_*`` functions must be +available). + +Swift Mailer does not work when used with function overloading as implemented +by ``mbstring`` when ``mbstring.func_overload`` is set to ``2``. + +Installation +------------ + +The recommended way to install Swiftmailer is via Composer: + +.. code-block:: bash + + $ composer require "swiftmailer/swiftmailer:^6.0" + +Basic Usage +----------- + +Here is the simplest way to send emails with Swift Mailer:: + + require_once '/path/to/vendor/autoload.php'; + + // Create the Transport + $transport = (new Swift_SmtpTransport('smtp.example.org', 25)) + ->setUsername('your username') + ->setPassword('your password') + ; + + // Create the Mailer using your created Transport + $mailer = new Swift_Mailer($transport); + + // Create a message + $message = (new Swift_Message('Wonderful Subject')) + ->setFrom(['john@doe.com' => 'John Doe']) + ->setTo(['receiver@domain.org', 'other@domain.org' => 'A name']) + ->setBody('Here is the message itself') + ; + + // Send the message + $result = $mailer->send($message); + +You can also use Sendmail as a transport:: + + // Sendmail + $transport = new Swift_SendmailTransport('/usr/sbin/sendmail -bs'); + +Getting Help +------------ + +For general support, use `Stack Overflow `_. + +For bug reports and feature requests, create a new ticket in `GitHub +`_. diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/doc/japanese.rst b/lib/composer/vendor/swiftmailer/swiftmailer/doc/japanese.rst new file mode 100644 index 00000000..54548217 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/doc/japanese.rst @@ -0,0 +1,19 @@ +Using Swift Mailer for Japanese Emails +====================================== + +To send emails in Japanese, you need to tweak the default configuration. + +Call the ``Swift::init()`` method with the following code as early as possible +in your code:: + + 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/lib/composer/vendor/swiftmailer/swiftmailer/doc/messages.rst b/lib/composer/vendor/swiftmailer/swiftmailer/doc/messages.rst new file mode 100644 index 00000000..03232cf8 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/doc/messages.rst @@ -0,0 +1,908 @@ +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 +--------------- + +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:: + + // Create the message + $message = (new Swift_Message()) + + // Give the message a subject + ->setSubject('Your subject') + + // Set the From address with an associative array + ->setFrom(['john@doe.com' => 'John Doe']) + + // Set the To addresses with an associative array (setTo/setCc/setBcc) + ->setTo(['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 DateTimeInterface instance 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()``:: + + $message = new Swift_Message(); + $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:: text + + 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 ``new Swift_Message()``:: + + // Pass it as a parameter when you create the message + $message = new Swift_Message('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. + +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:: + + // Pass it as a parameter when you create the message + $message = new Swift_Message('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. + +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. + +The attachment will be presented to the recipient as a downloadable file with +the same filename as the one you attached:: + + // 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. + +The attachment will be attached in the normal way, but meta-data sent inside +the email will rename the file to something else:: + + // 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 ``Swift_Attachment`` directly. + +The attachment will be presented to the recipient as a downloadable file +with the filename and content-type you specify:: + + // 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 = new Swift_Attachment($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 = (new Swift_Attachment()) + ->setFilename('my-file.pdf') + ->setContentType('application/pdf') + ->setBody($data) + ; + +.. 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. + +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. + +The attachment will be displayed within the email viewing window if the mail +client knows how to display it:: + + // 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') + ); + +.. 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. + +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. + +The file will be displayed with the message inline with the HTML wherever its ID +is used as a ``src`` attribute:: + + // Create the message + $message = new Swift_Message('My subject'); + + // Set the body + $message->setBody( + '' . + ' ' . + ' Here is an image 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 Image' . + ' Rest of message' . + ' ' . + '', + 'text/html' + ); + +.. 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:: + + // 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 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 ``new Swift_Image()`` method. + +The file will be displayed with the message inline with the HTML wherever its ID +is used as a ``src`` attribute:: + + // 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 = new Swift_Message('My subject'); + + // Set the body + $message->setBody( + '' . + ' ' . + ' Here is an image Image' . + ' Rest of message' . + ' ' . + '', + 'text/html' // Mark the content-type as HTML + ); + +.. 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:: + + // If placing the embed() code inline becomes cumbersome + // it's easy to do this in two steps + $cid = $message->embed(new Swift_Image($img_data, 'image.jpg', 'image/jpeg')); + + $message->setBody( + '' . + ' ' . + ' Here is an image 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:: + use Egulias\EmailValidator\EmailValidator; + use Egulias\EmailValidator\Validation\RFCValidation; + + $validator = new EmailValidator(); + $validator->isValid("example@example.com", new RFCValidation()); //true +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:: + + $message->setFrom('some@address.tld'); + + If you want to include a name then you must use an associative array:: + + $message->setFrom(['some@address.tld' => 'The Name']); + + If you want to include multiple addresses then you must use an array:: + + $message->setTo(['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:: + + $message->setTo([ + '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 ``new Swift_Message( ... )``, 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:: + + // Using setTo() to set all recipients in one go + $message->setTo([ + 'person1@example.org', + 'person2@otherdomain.org' => 'Person 2 Name', + 'person3@example.org', + 'person4@example.org', + 'person5@example.org' => 'Person 5 Name' + ]); + +.. 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:: + + // 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 ``new Swift_Message( ... )``, 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:: + + // Using setTo() to set all recipients in one go + $message->setTo([ + 'person1@example.org', + 'person2@otherdomain.org' => 'Person 2 Name', + 'person3@example.org', + 'person4@example.org', + 'person5@example.org' => 'Person 5 Name' + ]); + +.. 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:: + + // 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 ``new Swift_Message( ... )``, 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:: + + // Using setBcc() to set all recipients in one go + $message->setBcc([ + 'person1@example.org', + 'person2@otherdomain.org' => 'Person 2 Name', + 'person3@example.org', + 'person4@example.org', + 'person5@example.org' => 'Person 5 Name' + ]); + +.. 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:: + + // 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 realize 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. + +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. + +:: + + // Set a single From: address + $message->setFrom('your@address.tld'); + + // Set a From: address including a name + $message->setFrom(['your@address.tld' => 'Your Name']); + + // Set multiple From: addresses if multiple people wrote the email + $message->setFrom([ + '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. + +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:: + + $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. + +Bounce notifications will be sent to this address:: + + $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:: + + $message = new Swift_Message(); + + $smimeSigner = new Swift_Signers_SMimeSigner(); + $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:: + + $message = new Swift_Message(); + + $smimeSigner = new Swift_Signers_SMimeSigner(); + $smimeSigner->setSignCertificate('/path/to/certificate.pem', ['/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:: + + $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:: + + $message = new Swift_Message(); + + $smimeSigner = new Swift_Signers_SMimeSigner(); + $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:: + + $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()``: + + $message->setReadReceiptTo('your@address.tld'); + +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. + +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:: + + // Approach 1: Change the global setting (suggested) + Swift_Preferences::getInstance()->setCharset('iso-8859-2'); + + // Approach 2: Call the setCharset() method of the message + $message = (new Swift_Message()) + ->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:: + + $message->setMaxLineLength(1000); + +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 + +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. + +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:: + + // Indicate "High" priority + $message->setPriority(2); + +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: + +* ``Swift_Mime_SimpleMessage::PRIORITY_HIGHEST``: 1 +* ``Swift_Mime_SimpleMessage::PRIORITY_HIGH``: 2 +* ``Swift_Mime_SimpleMessage::PRIORITY_NORMAL``: 3 +* ``Swift_Mime_SimpleMessage::PRIORITY_LOW``: 4 +* ``Swift_Mime_SimpleMessage::PRIORITY_LOWEST``: 5 + +:: + + // Or use the constant to be more explicit + $message->setPriority(Swift_Mime_SimpleMessage::PRIORITY_HIGH); diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/doc/plugins.rst b/lib/composer/vendor/swiftmailer/swiftmailer/doc/plugins.rst new file mode 100644 index 00000000..c19c6d6a --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/doc/plugins.rst @@ -0,0 +1,337 @@ +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. + +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. + +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:: + + // Create the Mailer using any Transport + $mailer = new Swift_Mailer( + new Swift_SmtpTransport('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. + +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:: + + // Create the Mailer using any Transport + $mailer = new Swift_Mailer( + new Swift_SmtpTransport('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. + +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:: + + // Create the Mailer using any Transport + $mailer = new Swift_Mailer( + new Swift_SmtpTransport('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:: + + $replacements = []; + foreach ($users as $user) { + $replacements[$user['email']] = [ + '{username}'=>$user['username'], + '{resetcode}'=>$user['resetcode'] + ]; + } + +Now create an instance of the Decorator plugin using this array of replacements +and then register it with the Mailer. Do this only once! + +:: + + $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:: + + $message = (new Swift_Message()) + ->setSubject('Important notice for {username}') + ->setBody( + "Hello {username}, you requested to reset your password.\n" . + "Please visit https://example.com/pwreset and use the reset code {resetcode} to set a new password." + ) + ; + + 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,you requested to reset your password. + Please visit https://example.com/pwreset and use the reset code 183457 to set a new password. + +While another use may receive the message as: + +.. code-block:: text + + Subject: Important notice for billy-bo-bob + + Hello billy-bo-bob, you requested to reset your password. + Please visit https://example.com/pwreset and use the reset code 539127 to set a new password. + +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:: + + class DbReplacements implements Swift_Plugins_Decorator_Replacements { + public function getReplacementsFor($address) { + global $db; // Your PDO instance with a connection to your database + $query = $db->prepare( + "SELECT * FROM `users` WHERE `email` = ?" + ); + + $query->execute([$address]); + + if ($row = $query->fetch(PDO::FETCH_ASSOC)) { + return [ + '{username}'=>$row['username'], + '{resetcode}'=>$row['resetcode'] + ]; + } + } + } + +Now all you need to do is pass an instance of your class into the Decorator +plugin's constructor instead of passing an array:: + + $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/lib/composer/vendor/swiftmailer/swiftmailer/doc/sending.rst b/lib/composer/vendor/swiftmailer/swiftmailer/doc/sending.rst new file mode 100644 index 00000000..908959e6 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/doc/sending.rst @@ -0,0 +1,446 @@ +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. + +When using ``send()`` 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:: + + // Create the Transport + $transport = (new Swift_SmtpTransport('smtp.example.org', 25)) + ->setUsername('your username') + ->setPassword('your password') + ; + + /* + You could alternatively use a different transport such as Sendmail: + + // Sendmail + $transport = new Swift_SendmailTransport('/usr/sbin/sendmail -bs'); + */ + + // Create the Mailer using your created Transport + $mailer = new Swift_Mailer($transport); + + // Create a message + $message = (new Swift_Message('Wonderful Subject')) + ->setFrom(['john@doe.com' => 'John Doe']) + ->setTo(['receiver@domain.org', 'other@domain.org' => 'A name']) + ->setBody('Here is the message itself') + ; + + // Send the message + $result = $mailer->send($message); + +Transport Types +~~~~~~~~~~~~~~~ + +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:: + +* ``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_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). + +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. + +A connection to the SMTP server will be established upon the first call to +``send()``:: + + // Create the Transport + $transport = new Swift_SmtpTransport('smtp.example.org', 25); + + // Create the Mailer using your created Transport + $mailer = new Swift_Mailer($transport); + + /* + It's also possible to use multiple method calls + + $transport = (new Swift_SmtpTransport()) + ->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:: + + // Create the Transport + $transport = new Swift_SmtpTransport('smtp.example.org', 587, 'ssl'); + + // Create the Mailer using your created Transport + $mailer = new Swift_Mailer($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()``. + +SMTP with a Username and Password +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Some servers require authentication. You can provide a username and password +with ``setUsername()`` and ``setPassword()`` methods:: + + // Create the Transport the call setUsername() and setPassword() + $transport = (new Swift_SmtpTransport('smtp.example.org', 25)) + ->setUsername('username') + ->setPassword('password') + ; + + // Create the Mailer using your created Transport + $mailer = new Swift_Mailer($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. + +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 ``new +Swift_SendmailTransport()`` 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. + +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:: + + // Create the Transport + $transport = new Swift_SendmailTransport('/usr/sbin/exim -bs'); + + // Create the Mailer using your created Transport + $mailer = new Swift_Mailer($transport); + +Available Methods for Sending Messages +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Mailer class offers one method for sending Messages -- ``send()``. + +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. ``send()`` 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. + +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:: + + // Create the Transport + $transport = new Swift_SmtpTransport('localhost', 25); + + // Create the Mailer using your created Transport + $mailer = new Swift_Mailer($transport); + + // Create a message + $message = (new Swift_Message('Wonderful Subject')) + ->setFrom(['john@doe.com' => 'John Doe']) + ->setTo(['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``, + 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:: + + // Create the Transport + $transport = new Swift_SmtpTransport('localhost', 25); + + // Create the Mailer using your created Transport + $mailer = new Swift_Mailer($transport); + + // Create a message + $message = (new Swift_Message('Wonderful Subject')) + ->setFrom(['john@doe.com' => 'John Doe']) + ->setBody('Here is the message itself') + ; + + // Send the message + $failedRecipients = []; + $numSent = 0; + $to = ['receiver@domain.org', 'other@domain.org' => 'A name']; + + foreach ($to as $address => $name) + { + if (is_int($address)) { + $message->setTo($name); + } else { + $message->setTo([$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:: + + $mailer = new Swift_Mailer( ... ); + + $message = (new Swift_Message( ... )) + ->setFrom( ... ) + ->setTo([ + '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 + ) + */ + +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. diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php new file mode 100644 index 00000000..e89703ea --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift.php @@ -0,0 +1,79 @@ +createDependenciesFor('mime.attachment') + ); + + $this->setBody($data); + $this->setFilename($filename); + if ($contentType) { + $this->setContentType($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 (new self())->setFile( + new Swift_ByteStream_FileByteStream($path), + $contentType + ); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php new file mode 100644 index 00000000..bfd2c79b --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php @@ -0,0 +1,181 @@ +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 + * + * @throws Swift_IoException + * + * @return int + */ + 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->doCommit($this->filter($bytes)); + + foreach ($this->mirrors as $stream) { + $stream->write($bytes); + } + + $this->writeBuffer = ''; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php new file mode 100644 index 00000000..31b85e0e --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php @@ -0,0 +1,182 @@ +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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php new file mode 100644 index 00000000..61f820e5 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php @@ -0,0 +1,216 @@ +path = $path; + $this->mode = $writable ? 'w+b' : 'rb'; + } + + /** + * 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)) { + $bytes = fread($fp, $length); + $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 doCommit($bytes) + { + fwrite($this->getWriteHandle(), $bytes); + $this->resetReadHandle(); + } + + /** Not used */ + protected function flush() + { + } + + /** Get the resource for reading */ + private function getReadHandle() + { + if (!isset($this->reader)) { + $pointer = @fopen($this->path, 'rb'); + if (!$pointer) { + throw new Swift_IoException('Unable to open file for reading ['.$this->path.']'); + } + $this->reader = $pointer; + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php new file mode 100644 index 00000000..1c9a80c0 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader.php new file mode 100644 index 00000000..4267adbc --- /dev/null +++ b/lib/composer/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 int[] $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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php new file mode 100644 index 00000000..b09bb5b6 --- /dev/null +++ b/lib/composer/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 = $ignored ? 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php new file mode 100644 index 00000000..67da48f6 --- /dev/null +++ b/lib/composer/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; + } + + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php new file mode 100644 index 00000000..22746bd8 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php @@ -0,0 +1,176 @@ + + */ +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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php new file mode 100644 index 00000000..15b6c692 --- /dev/null +++ b/lib/composer/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 = strtolower(trim($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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream.php new file mode 100644 index 00000000..717924f5 --- /dev/null +++ b/lib/composer/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 int[] + */ + 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 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php new file mode 100644 index 00000000..0d62fa68 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php @@ -0,0 +1,267 @@ + + */ +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: + $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 int[] + */ + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ConfigurableSpool.php new file mode 100644 index 00000000..a711bac4 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php new file mode 100644 index 00000000..b1bc3306 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyContainer.php @@ -0,0 +1,373 @@ +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 $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + 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) + ); + } + + 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; + } + + return $this->lookup($item); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/DependencyException.php new file mode 100644 index 00000000..799d38d8 --- /dev/null +++ b/lib/composer/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 from a filesystem path. + * + * @param string $path + * + * @return Swift_Mime_EmbeddedFile + */ + public static function fromPath($path) + { + return (new self())->setFile(new Swift_ByteStream_FileByteStream($path)); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php new file mode 100644 index 00000000..2073abca --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder.php @@ -0,0 +1,28 @@ += $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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php new file mode 100644 index 00000000..b23b0770 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php @@ -0,0 +1,300 @@ + '=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); + + $i = strpos($enc, '=0D=0A'); + $newLineLength = $lineLen + ($i === false ? $size : $i); + + if ($currentLine && $newLineLength >= $thisLineLength) { + $lines[$lNo] = ''; + $currentLine = &$lines[$lNo++]; + $thisLineLength = $maxLineLength; + $lineLen = 0; + } + + $currentLine .= $enc; + + if ($i === false) { + $lineLen += $size; + } else { + // 6 is the length of '=0D=0A'. + $lineLen = $size - strrpos($enc, '=0D=0A') - 6; + } + } + + 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 int[] $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 int[] + */ + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php new file mode 100644 index 00000000..bebb1349 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandEvent.php new file mode 100644 index 00000000..9834aa95 --- /dev/null +++ b/lib/composer/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 int[] + */ + public function getSuccessCodes() + { + return $this->successCodes; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/CommandListener.php new file mode 100644 index 00000000..7545404e --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php new file mode 100644 index 00000000..5ae6c04b --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/ResponseListener.php new file mode 100644 index 00000000..c40919d2 --- /dev/null +++ b/lib/composer/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_SimpleMessage + */ + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/SendListener.php new file mode 100644 index 00000000..d922e1bf --- /dev/null +++ b/lib/composer/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_SimpleMessage + * + * @return Swift_Events_SendEvent + */ + public function createSendEvent(Swift_Transport $source, Swift_Mime_SimpleMessage $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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php new file mode 100644 index 00000000..a8972fda --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php @@ -0,0 +1,27 @@ +getSource(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php new file mode 100644 index 00000000..253165de --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php new file mode 100644 index 00000000..cc3c0993 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php @@ -0,0 +1,24 @@ +createDependenciesFor('transport.failover') + ); + + $this->setTransports($transports); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileSpool.php new file mode 100644 index 00000000..b0b9eb06 --- /dev/null +++ b/lib/composer/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(sprintf('Unable to create path "%s".', $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_SimpleMessage $message The message to store + * + * @throws Swift_IoException + * + * @return bool + */ + public function queueMessage(Swift_Mime_SimpleMessage $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', 'xb'); + 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(sprintf('Unable to create a file for enqueuing Message in "%s".', $this->path)); + } + + /** + * 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[random_int(0, $strlen - 1)]; + } + + return $ret; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php new file mode 100644 index 00000000..0b24db1c --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/FileStream.php @@ -0,0 +1,24 @@ +setFile(new Swift_ByteStream_FileByteStream($path)); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/InputByteStream.php new file mode 100644 index 00000000..56efc759 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php new file mode 100644 index 00000000..d6a633a1 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php @@ -0,0 +1,298 @@ +stream = $stream; + $this->path = $path; + } + + /** + * 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 + * + * @throws Swift_IoException + * + * @return string + */ + public function getString($nsKey, $itemKey) + { + $this->prepareCache($nsKey); + if ($this->hasKey($nsKey, $itemKey)) { + $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_START); + $str = ''; + while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { + $str .= $bytes; + } + $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); + while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { + $is->write($bytes); + } + $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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php new file mode 100644 index 00000000..af80bdca --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php new file mode 100644 index 00000000..03106e55 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php @@ -0,0 +1,33 @@ +createDependenciesFor('transport.loadbalanced') + ); + + $this->setTransports($transports); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php new file mode 100644 index 00000000..3561ec6e --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer.php @@ -0,0 +1,102 @@ +transport = $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_SimpleMessage $message + * @param array $failedRecipients An array of failures by-reference + * + * @return int The number of successful recipients. Can be 0 which indicates failure + */ + public function send(Swift_Mime_SimpleMessage $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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php new file mode 100644 index 00000000..84dacb5f --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php new file mode 100644 index 00000000..650f3ec3 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php new file mode 100644 index 00000000..9aa62835 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MemorySpool.php @@ -0,0 +1,110 @@ + + * + * 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(); + private $flushRetries = 3; + + /** + * 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() + { + } + + /** + * @param int $retries + */ + public function setFlushRetries($retries) + { + $this->flushRetries = $retries; + } + + /** + * Stores a message in the queue. + * + * @param Swift_Mime_SimpleMessage $message The message to store + * + * @return bool Whether the operation has succeeded + */ + public function queueMessage(Swift_Mime_SimpleMessage $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; + $retries = $this->flushRetries; + while ($retries--) { + try { + while ($message = array_pop($this->messages)) { + $count += $transport->send($message, $failedRecipients); + } + } catch (Swift_TransportException $exception) { + if ($retries) { + // re-queue the message at the end of the queue to give a chance + // to the other messages to be sent, in case the failure was due to + // this message and not just the transport failing + array_unshift($this->messages, $message); + + // wait half a second before we try again + usleep(500000); + } else { + throw $exception; + } + } + } + + return $count; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php new file mode 100644 index 00000000..00f6e160 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Message.php @@ -0,0 +1,274 @@ +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); + } + } + + /** + * Add a MimePart to this Message. + * + * @param string|Swift_OutputByteStream $body + * @param string $contentType + * @param string $charset + * + * @return $this + */ + public function addPart($body, $contentType = null, $charset = null) + { + return $this->attach((new Swift_MimePart($body, $contentType, $charset))->setEncoder($this->getEncoder())); + } + + /** + * Detach a signature handler from a message. + * + * @param Swift_Signer $signer + * + * @return $this + */ + 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 $this + */ + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php new file mode 100644 index 00000000..a36ce723 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Attachment.php @@ -0,0 +1,149 @@ +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 $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php new file mode 100644 index 00000000..b49c3a87 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php @@ -0,0 +1,24 @@ += $maxLineLength || 76 < $maxLineLength) { + $maxLineLength = 76; + } + + $remainder = 0; + $base64ReadBufferRemainderBytes = null; + + // To reduce memory usage, the output buffer is streamed to the input buffer like so: + // Output Stream => base64encode => wrap line length => Input Stream + // HOWEVER it's important to note that base64_encode() should only be passed whole triplets of data (except for the final chunk of data) + // otherwise it will assume the input data has *ended* and it will incorrectly pad/terminate the base64 data mid-stream. + // We use $base64ReadBufferRemainderBytes to carry over 1-2 "remainder" bytes from the each chunk from OutputStream and pre-pend those onto the + // chunk of bytes read in the next iteration. + // When the OutputStream is empty, we must flush any remainder bytes. + while (true) { + $readBytes = $os->read(8192); + $atEOF = ($readBytes === false); + + if ($atEOF) { + $streamTheseBytes = $base64ReadBufferRemainderBytes; + } else { + $streamTheseBytes = $base64ReadBufferRemainderBytes.$readBytes; + } + $base64ReadBufferRemainderBytes = null; + $bytesLength = strlen($streamTheseBytes); + + if ($bytesLength === 0) { // no data left to encode + break; + } + + // if we're not on the last block of the ouput stream, make sure $streamTheseBytes ends with a complete triplet of data + // and carry over remainder 1-2 bytes to the next loop iteration + if (!$atEOF) { + $excessBytes = $bytesLength % 3; + if ($excessBytes !== 0) { + $base64ReadBufferRemainderBytes = substr($streamTheseBytes, -$excessBytes); + $streamTheseBytes = substr($streamTheseBytes, 0, $bytesLength - $excessBytes); + } + } + + $encoded = base64_encode($streamTheseBytes); + $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); + + if ($atEOF) { + break; + } + } + } + + /** + * Get the name of this encoding scheme. + * Returns the string 'base64'. + * + * @return string + */ + public function getName() + { + return 'base64'; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php new file mode 100644 index 00000000..34de4ef3 --- /dev/null +++ b/lib/composer/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 + * + * @throws RuntimeException + * + * @return string + */ + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php new file mode 100644 index 00000000..b3577dbe --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php @@ -0,0 +1,134 @@ +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); + + $i = strpos($enc, '=0D=0A'); + $newLineLength = $lineLen + ($i === false ? $size : $i); + + if ($currentLine && $newLineLength >= $thisLineLength) { + $is->write($prepend.$this->standardize($currentLine)); + $currentLine = ''; + $prepend = "=\r\n"; + $thisLineLength = $maxLineLength; + $lineLen = 0; + } + + $currentLine .= $enc; + + if ($i === false) { + $lineLen += $size; + } else { + // 6 is the length of '=0D=0A'. + $lineLen = $size - strrpos($enc, '=0D=0A') - 6; + } + } + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php new file mode 100644 index 00000000..3214e1cf --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php @@ -0,0 +1,98 @@ + + */ +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; + $this->safeEncoder->charsetChanged($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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php new file mode 100644 index 00000000..0b8526e3 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php @@ -0,0 +1,64 @@ + + */ +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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php new file mode 100644 index 00000000..7835a492 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php new file mode 100644 index 00000000..cc44a6ef --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php @@ -0,0 +1,24 @@ +getName(), "\r\n"); + mb_internal_encoding($old); + + return $newstring; + } + + return parent::encodeString($string, $firstLineOffset, $maxLineLength); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php new file mode 100644 index 00000000..062be7d7 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/AbstractHeader.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/AbstractHeader.php new file mode 100644 index 00000000..a569f816 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/AbstractHeader.php @@ -0,0 +1,481 @@ +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; + } + + /** + * 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(); + } + + /** + * 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('/^'.self::PHRASE_PATTERN.'$/D', $phraseStr)) { + // .. but it is just ascii text, try escaping some characters + // and make it a quoted-string + if (preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $phraseStr)) { + $phraseStr = $this->escapeSpecials($phraseStr, array('"')); + $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; + } + + /** + * Escape special characters in a string (convert to quoted-pairs). + * + * @param string $token + * @param string[] $include additional chars to escape + * + * @return string + */ + private function escapeSpecials($token, $include = array()) + { + foreach (array_merge(array('\\'), $include) as $char) { + $token = str_replace($char, '\\'.$char, $token); + } + + return $token; + } + + /** + * 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 (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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php new file mode 100644 index 00000000..6dcc92bf --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php @@ -0,0 +1,115 @@ +setFieldName($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_DATE; + } + + /** + * Set the model for the field body. + * + * @param DateTimeInterface $model + */ + public function setFieldBodyModel($model) + { + $this->setDateTime($model); + } + + /** + * Get the model for the field body. + * + * @return DateTimeImmutable + */ + public function getFieldBodyModel() + { + return $this->getDateTime(); + } + + /** + * Get the date-time representing the Date in this Header. + * + * @return DateTimeImmutable + */ + public function getDateTime() + { + return $this->dateTime; + } + + /** + * Set the date-time of the Date in this Header. + * + * If a DateTime instance is provided, it is converted to DateTimeImmutable. + * + * @param DateTimeInterface $dateTime + */ + public function setDateTime(DateTimeInterface $dateTime) + { + $this->clearCachedValueIf($this->getCachedValue() != $dateTime->format(DateTime::RFC2822)); + if ($dateTime instanceof DateTime) { + $immutable = new DateTimeImmutable('@'.$dateTime->getTimestamp()); + $dateTime = $immutable->setTimezone($dateTime->getTimezone()); + } + $this->dateTime = $dateTime; + } + + /** + * 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->dateTime)) { + $this->setCachedValue($this->dateTime->format(DateTime::RFC2822)); + } + } + + return $this->getCachedValue(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php new file mode 100644 index 00000000..acf79447 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php @@ -0,0 +1,184 @@ +setFieldName($name); + $this->emailValidator = $emailValidator; + } + + /** + * 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() + * + * @throws Swift_RfcComplianceException + * + * @return string + */ + 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 (!$this->emailValidator->isValid($id, new RFCValidation())) { + throw new Swift_RfcComplianceException('Invalid ID given <'.$id.'>'); + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php new file mode 100644 index 00000000..450e0f25 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php @@ -0,0 +1,359 @@ +setFieldName($name); + $this->setEncoder($encoder); + $this->emailValidator = $emailValidator; + } + + /** + * 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()} + * + * @throws Swift_RfcComplianceException + * + * @return array + */ + 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() + * + * @throws Swift_RfcComplianceException + * + * @return string[] + */ + 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() + * + * @throws Swift_RfcComplianceException + * + * @return string + */ + public function getFieldBody() + { + // Compute the string value of the header only if needed + if (null === $this->getCachedValue()) { + $this->setCachedValue($this->createMailboxListString($this->mailboxes)); + } + + return $this->getCachedValue(); + } + + /** + * 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 + * + * @throws Swift_RfcComplianceException + * + * @return string + */ + protected function createMailboxListString(array $mailboxes) + { + return implode(', ', $this->createNameAddressStrings($mailboxes)); + } + + /** + * Redefine the encoding requirements for mailboxes. + * + * All "specials" must be encoded as the full header value will not be quoted + * + * @see RFC 2822 3.2.1 + * + * @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 (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 (!$this->emailValidator->isValid($address, new RFCValidation())) { + throw new Swift_RfcComplianceException( + 'Address in mailbox given ['.$address.'] does not comply with RFC 2822, 3.6.2.' + ); + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php new file mode 100644 index 00000000..29277994 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php @@ -0,0 +1,133 @@ + + */ +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; + + /** + * @param string $name + */ + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php new file mode 100644 index 00000000..b4a0ddf1 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php @@ -0,0 +1,257 @@ +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 $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 (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 (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('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php new file mode 100644 index 00000000..f79e19fd --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php @@ -0,0 +1,152 @@ +setFieldName($name); + $this->emailValidator = $emailValidator; + } + + /** + * 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 (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 (!$this->emailValidator->isValid($address, new RFCValidation())) { + throw new Swift_RfcComplianceException( + 'Address set in PathHeader does not comply with addr-spec of RFC 2822.' + ); + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php new file mode 100644 index 00000000..d9d9f5e2 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php @@ -0,0 +1,110 @@ +setFieldName($name); + $this->setEncoder($encoder); + } + + /** + * 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/IdGenerator.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/IdGenerator.php new file mode 100644 index 00000000..6e98ee89 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/IdGenerator.php @@ -0,0 +1,53 @@ +idRight = $idRight; + } + + /** + * Returns the right-hand side of the "@" used in all generated IDs. + * + * @return string + */ + public function getIdRight() + { + return $this->idRight; + } + + /** + * Sets the right-hand side of the "@" to use in all generated IDs. + * + * @param string $idRight + */ + public function setIdRight($idRight) + { + $this->idRight = $idRight; + } + + /** + * @return string + */ + public function generateId() + { + $idLeft = bin2hex(random_bytes(16)); // set 32 hex values + + return $idLeft.'@'.$this->idRight; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimePart.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimePart.php new file mode 100644 index 00000000..d49449fe --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/MimePart.php @@ -0,0 +1,212 @@ +setContentType('text/plain'); + if (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 $this + */ + 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 $this + */ + 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 $this + */ + 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 'yes' === $this->getHeaderParameter('Content-Type', 'delsp'); + } + + /** + * Turn delsp on or off for this entity. + * + * @param bool $delsp + * + * @return $this + */ + 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', 'iso-8859-15', ''))) { + // 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderFactory.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderFactory.php new file mode 100644 index 00000000..e14c9d6f --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderFactory.php @@ -0,0 +1,197 @@ +encoder = $encoder; + $this->paramEncoder = $paramEncoder; + $this->emailValidator = $emailValidator; + $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->emailValidator); + if (isset($addresses)) { + $header->setFieldBodyModel($addresses); + } + $this->setHeaderCharset($header); + + return $header; + } + + /** + * Create a new Date header using $dateTime. + * + * @param string $name + * @param DateTimeInterface|null $dateTime + * + * @return Swift_Mime_Header + */ + public function createDateHeader($name, DateTimeInterface $dateTime = null) + { + $header = new Swift_Mime_Headers_DateHeader($name); + if (isset($dateTime)) { + $header->setFieldBodyModel($dateTime); + } + $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); + 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_Headers_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); + 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->emailValidator); + 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->emailValidator); + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php new file mode 100644 index 00000000..6f71fcac --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php @@ -0,0 +1,409 @@ +factory = $factory; + if (isset($charset)) { + $this->setCharset($charset); + } + } + + public function newInstance() + { + return new self($this->factory); + } + + /** + * 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 $dateTime. + * + * @param string $name + * @param DateTimeInterface $dateTime + */ + public function addDateHeader($name, DateTimeInterface $dateTime = null) + { + $this->storeHeader($name, + $this->factory->createDateHeader($name, $dateTime)); + } + + /** + * 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); + + if (!array_key_exists($lowerName, $this->headers)) { + return false; + } + + if (func_num_args() < 2) { + // index was not specified, so we only need to check that there is at least one header value set + return (bool) count($this->headers[$lowerName]); + } + + return 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) + { + $name = strtolower($name); + + if (func_num_args() < 2) { + if ($this->has($name)) { + $values = array_values($this->headers[$name]); + + return array_shift($values); + } + } else { + if ($this->has($name, $index)) { + return $this->headers[$name][$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]); + } + + /** + * 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 (-1 === $aPos && -1 === $bPos) { + // just be sure to be determinist here + return $a > $b ? -1 : 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php new file mode 100644 index 00000000..768de07f --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php @@ -0,0 +1,655 @@ +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(new DateTimeImmutable()); + $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 $this + */ + 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 DateTimeInterface $dateTime + * + * @return $this + */ + public function setDate(DateTimeInterface $dateTime) + { + if (!$this->setHeaderFieldModel('Date', $dateTime)) { + $this->getHeaders()->addDateHeader('Date', $dateTime); + } + + return $this; + } + + /** + * Get the date at which this message was created. + * + * @return DateTimeInterface + */ + public function getDate() + { + return $this->getHeaderFieldModel('Date'); + } + + /** + * Set the return-path (the bounce address) of this message. + * + * @param string $address + * + * @return $this + */ + 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 $this + */ + 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 $this + */ + 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|array $addresses + * @param string $name optional + * + * @return $this + */ + 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 $this + */ + 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 mixed $addresses + * @param string $name optional + * + * @return $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + public function setPriority($priority) + { + $priorityMap = array( + self::PRIORITY_HIGHEST => 'Highest', + self::PRIORITY_HIGH => 'High', + self::PRIORITY_NORMAL => 'Normal', + self::PRIORITY_LOW => 'Low', + self::PRIORITY_LOWEST => '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 $priority ?? 3; + } + + /** + * Ask for a delivery receipt from the recipient to be sent to $addresses. + * + * @param array $addresses + * + * @return $this + */ + 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_SimpleMimeEntity} such as an Attachment or MimePart. + * + * @param Swift_Mime_SimpleMimeEntity $entity + * + * @return $this + */ + public function attach(Swift_Mime_SimpleMimeEntity $entity) + { + $this->setChildren(array_merge($this->getChildren(), array($entity))); + + return $this; + } + + /** + * Remove an already attached entity. + * + * @param Swift_Mime_SimpleMimeEntity $entity + * + * @return $this + */ + public function detach(Swift_Mime_SimpleMimeEntity $entity) + { + $newChildren = array(); + foreach ($this->getChildren() as $child) { + if ($entity !== $child) { + $newChildren[] = $child; + } + } + $this->setChildren($newChildren); + + return $this; + } + + /** + * Attach a {@link Swift_Mime_SimpleMimeEntity} and return it's CID source. + * This method should be used when embedding images or other data in a message. + * + * @param Swift_Mime_SimpleMimeEntity $entity + * + * @return string + */ + public function embed(Swift_Mime_SimpleMimeEntity $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->getIdGenerator(), $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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php new file mode 100644 index 00000000..2d1a9b47 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php @@ -0,0 +1,823 @@ + 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_SimpleHeaderSet $headers + * @param Swift_Mime_ContentEncoder $encoder + * @param Swift_KeyCache $cache + * @param Swift_IdGenerator $idGenerator + */ + public function __construct(Swift_Mime_SimpleHeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_IdGenerator $idGenerator) + { + $this->cacheKey = bin2hex(random_bytes(16)); // set 32 hex values + $this->cache = $cache; + $this->headers = $headers; + $this->idGenerator = $idGenerator; + $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->idGenerator->generateId(); + } + + /** + * Generate a new Content-ID or Message-ID for this MIME entity. + * + * @return string + */ + public function generateId() + { + $this->setId($this->idGenerator->generateId()); + + return $this->id; + } + + /** + * Get the {@link Swift_Mime_SimpleHeaderSet} for this entity. + * + * @return Swift_Mime_SimpleHeaderSet + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + public function setMaxLineLength($length) + { + $this->maxLineLength = $length; + + return $this; + } + + /** + * Get all children added to this entity. + * + * @return Swift_Mime_SimpleMimeEntity[] + */ + public function getChildren() + { + return $this->children; + } + + /** + * Set all children of this entity. + * + * @param Swift_Mime_SimpleMimeEntity[] $children + * @param int $compoundLevel For internal use only + * + * @return $this + */ + public function setChildren(array $children, $compoundLevel = null) + { + // TODO: Try to refactor this logic + $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 ($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 $this + */ + 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 $this + */ + 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_'.time().'_'.bin2hex(random_bytes(16)).'_=_'; + } + + return $this->boundary; + } + + /** + * Set the boundary used to separate children in this entity. + * + * @param string $boundary + * + * @throws Swift_RfcComplianceException + * + * @return $this + */ + 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; + } + + 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; + } + + 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 ID generator. + * + * @return Swift_IdGenerator + */ + protected function getIdGenerator() + { + return $this->idGenerator; + } + + /** + * Empty the KeyCache for this entity. + */ + protected function clearCache() + { + $this->cache->clearKey($this->cacheKey, 'body'); + } + + private function readStream(Swift_OutputByteStream $os) + { + $string = ''; + while (false !== $bytes = $os->read(8192)) { + $string .= $bytes; + } + + $os->setReadPointer(0); + + 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]; + } + + return $realLevel; + } + + private function createChild() + { + return new self($this->headers->newInstance(), $this->encoder, $this->cache, $this->idGenerator); + } + + 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) { + // Group the messages by order of preference + $sorted = array(); + foreach ($this->immediateChildren as $child) { + $type = $child->getContentType(); + $level = array_key_exists($type, $this->alternativePartOrder) ? $this->alternativePartOrder[$type] : max($this->alternativePartOrder) + 1; + + if (empty($sorted[$level])) { + $sorted[$level] = array(); + } + + $sorted[$level][] = $child; + } + + ksort($sorted); + + $this->immediateChildren = array_reduce($sorted, 'array_merge', array()); + } + } + + /** + * Empties it's own contents from the cache. + */ + public function __destruct() + { + if ($this->cache instanceof Swift_KeyCache) { + $this->cache->clearAll($this->cacheKey); + } + } + + /** + * Make a deep copy of object. + */ + public function __clone() + { + $this->headers = clone $this->headers; + $this->encoder = clone $this->encoder; + $this->cacheKey = bin2hex(random_bytes(16)); // set 32 hex values + $children = array(); + foreach ($this->children as $pos => $child) { + $children[$pos] = clone $child; + } + $this->setChildren($children); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php new file mode 100644 index 00000000..8fa0cbeb --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/MimePart.php @@ -0,0 +1,45 @@ +createDependenciesFor('mime.part') + ); + + if (!isset($charset)) { + $charset = Swift_DependencyContainer::getInstance() + ->lookup('properties.charset'); + } + $this->setBody($body); + $this->setCharset($charset); + if ($contentType) { + $this->setContentType($contentType); + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php new file mode 100644 index 00000000..a580dfbe --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/NullTransport.php @@ -0,0 +1,26 @@ + + * + * 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 +{ + public function __construct() + { + call_user_func_array( + array($this, 'Swift_Transport_NullTransport::__construct'), + Swift_DependencyContainer::getInstance() + ->createDependenciesFor('transport.null') + ); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/OutputByteStream.php new file mode 100644 index 00000000..1f26f9be --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php new file mode 100644 index 00000000..af060a99 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php new file mode 100644 index 00000000..9f9f08b5 --- /dev/null +++ b/lib/composer/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; + } + } + } elseif (is_string($body)) { + $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); + } + + return $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_SimpleMessage $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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php new file mode 100644 index 00000000..b975d36b --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php @@ -0,0 +1,69 @@ +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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Logger.php new file mode 100644 index 00000000..d9bce893 --- /dev/null +++ b/lib/composer/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(); + $code = $e->getCode(); + $this->logger->add(sprintf('!! %s (code: %s)', $message, $code)); + $message .= PHP_EOL; + $message .= 'Log data:'.PHP_EOL; + $message .= $this->logger->dump(); + $evt->cancelBubble(); + throw new Swift_TransportException($message, $code, $e->getPrevious()); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php new file mode 100644 index 00000000..186b6b41 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php new file mode 100644 index 00000000..40a53d2b --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php new file mode 100644 index 00000000..5ff1d932 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php @@ -0,0 +1,74 @@ +messages = array(); + } + + /** + * Get the message list. + * + * @return Swift_Mime_Message[] + */ + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php new file mode 100644 index 00000000..fb99e4c9 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php @@ -0,0 +1,31 @@ +host = $host; + $this->port = $port; + $this->crypto = $crypto; + } + + /** + * Set a Pop3Connection to delegate to instead of connecting directly. + * + * @param Swift_Plugins_Pop_Pop3Connection $connection + * + * @return $this + */ + 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 $this + */ + public function setTimeout($timeout) + { + $this->timeout = (int) $timeout; + + return $this; + } + + /** + * Set the username to use when connecting (if needed). + * + * @param string $username + * + * @return $this + */ + public function setUsername($username) + { + $this->username = $username; + + return $this; + } + + /** + * Set the password to use when connecting (if needed). + * + * @param string $password + * + * @return $this + */ + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php new file mode 100644 index 00000000..8d797dd1 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php @@ -0,0 +1,213 @@ +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_SimpleHeaderSet $headerSet + * @param string $type + */ + private function filterHeaderSet(Swift_Mime_SimpleHeaderSet $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_SimpleMessage $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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporter.php new file mode 100644 index 00000000..3a2b6657 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php new file mode 100644 index 00000000..67c117ac --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php new file mode 100644 index 00000000..525eef57 --- /dev/null +++ b/lib/composer/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; + echo 'FAIL '.$address.PHP_EOL; + echo '
'.PHP_EOL; + flush(); + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php new file mode 100644 index 00000000..595c0f60 --- /dev/null +++ b/lib/composer/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(); + } + + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Plugins/Timer.php new file mode 100644 index 00000000..9c8deb38 --- /dev/null +++ b/lib/composer/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 $this + */ + 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 $this + */ + 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 $this + */ + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php new file mode 100644 index 00000000..2897474e --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php @@ -0,0 +1,27 @@ +createDependenciesFor('transport.sendmail') + ); + + $this->setCommand($command); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php new file mode 100644 index 00000000..2d8176d9 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signer.php @@ -0,0 +1,20 @@ + + */ +interface Swift_Signer +{ + public function reset(); +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/BodySigner.php new file mode 100644 index 00000000..8e66e18f --- /dev/null +++ b/lib/composer/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 self + */ + public function signMessage(Swift_Message $message); + + /** + * Return the list of header a signer might tamper. + * + * @return array + */ + public function getAlteredHeaders(); +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php new file mode 100644 index 00000000..a88daa19 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php @@ -0,0 +1,686 @@ + + */ +class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner +{ + /** + * PrivateKey. + * + * @var string + */ + protected $privateKey; + + /** + * DomainName. + * + * @var string + */ + protected $domainName; + + /** + * Selector. + * + * @var string + */ + protected $selector; + + private $passphrase = ''; + + /** + * Hash algorithm used. + * + * @see RFC6376 3.3: Signers MUST implement and SHOULD sign using rsa-sha256. + * + * @var string + */ + protected $hashAlgorithm = 'rsa-sha256'; + + /** + * 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('return-path' => true); + + /** + * Signer identity. + * + * @var string + */ + 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, otherwise 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 debugData here. + * + * @var string + */ + private $debugHeadersData = ''; + + /** + * Stores the bodyHash. + * + * @var string + */ + private $bodyHash = ''; + + /** + * Stores the signature header. + * + * @var Swift_Mime_Headers_ParameterizedHeader + */ + protected $dkimHeader; + + 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 + * @param string $passphrase + */ + public function __construct($privateKey, $domainName, $selector, $passphrase = '') + { + $this->privateKey = $privateKey; + $this->domainName = $domainName; + $this->signerIdentity = '@'.$domainName; + $this->selector = $selector; + $this->passphrase = $passphrase; + } + + /** + * Reset the Signer. + * + * @see Swift_Signer::reset() + */ + public function reset() + { + $this->headerHash = null; + $this->signedHeaders = array(); + $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 + */ + // TODO fix return + 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. + */ + 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; + } + } + } + + /** + * 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. + * + * @param string $hash 'rsa-sha1' or 'rsa-sha256' + * + * @throws Swift_SwiftException + * + * @return $this + */ + public function setHashAlgorithm($hash) + { + switch ($hash) { + case 'rsa-sha1': + $this->hashAlgorithm = 'rsa-sha1'; + break; + case 'rsa-sha256': + $this->hashAlgorithm = 'rsa-sha256'; + if (!defined('OPENSSL_ALGO_SHA256')) { + throw new Swift_SwiftException('Unable to set sha256 as it is not supported by OpenSSL.'); + } + break; + default: + throw new Swift_SwiftException('Unable to set the hash algorithm, must be one of rsa-sha1 or rsa-sha256 (%s given).', $hash); + } + + return $this; + } + + /** + * Set the body canonicalization algorithm. + * + * @param string $canon + * + * @return $this + */ + 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 $this + */ + public function setHeaderCanon($canon) + { + if ($canon == 'relaxed') { + $this->headerCanon = 'relaxed'; + } else { + $this->headerCanon = 'simple'; + } + + return $this; + } + + /** + * Set the signer identity. + * + * @param string $identity + * + * @return $this + */ + public function setSignerIdentity($identity) + { + $this->signerIdentity = $identity; + + return $this; + } + + /** + * Set the length of the body to sign. + * + * @param mixed $len (bool or int) + * + * @return $this + */ + 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 int $time A timestamp + * + * @return $this + */ + public function setSignatureTimestamp($time) + { + $this->signatureTimestamp = $time; + + return $this; + } + + /** + * Set the signature expiration timestamp. + * + * @param int $time A timestamp + * + * @return $this + */ + 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_SimpleHeaderSet $headers + * + * @return Swift_Signers_DKIMSigner + */ + public function setHeaders(Swift_Mime_SimpleHeaderSet $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_SimpleHeaderSet $headers + * + * @return Swift_Signers_DKIMSigner + */ + public function addSignature(Swift_Mime_SimpleHeaderSet $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); + 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 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, $this->passphrase); + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php new file mode 100644 index 00000000..40654987 --- /dev/null +++ b/lib/composer/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; + } + + /** + * Resets internal states. + * + * @return $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + 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]); + + break; + } + } + + return $this; + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + * + * @throws Swift_IoException + * + * @return $this + */ + 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 $this + */ + public function setHashAlgorithm($hash) + { + $this->hashAlgorithm = 'rsa-sha1'; + + return $this; + } + + /** + * Set the canonicalization algorithm. + * + * @param string $canon simple | nofws defaults to simple + * + * @return $this + */ + public function setCanon($canon) + { + if ($canon == 'nofws') { + $this->canon = 'nofws'; + } else { + $this->canon = 'simple'; + } + + return $this; + } + + /** + * Set the signer identity. + * + * @param string $identity + * + * @return $this + */ + public function setSignerIdentity($identity) + { + $this->signerIdentity = $identity; + + return $this; + } + + /** + * Enable / disable the DebugHeaders. + * + * @param bool $debug + * + * @return $this + */ + 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'); + } + + return array('DomainKey-Signature'); + } + + /** + * Adds an ignored Header. + * + * @param string $header_name + * + * @return $this + */ + public function ignoreHeader($header_name) + { + $this->ignoredHeaders[strtolower($header_name)] = true; + + return $this; + } + + /** + * Set the headers to sign. + * + * @param Swift_Mime_SimpleHeaderSet $headers + * + * @return $this + */ + public function setHeaders(Swift_Mime_SimpleHeaderSet $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_SimpleHeaderSet $headers + * + * @return $this + */ + public function addSignature(Swift_Mime_SimpleHeaderSet $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->bodyCanonLine = ''; + } + + /** + * @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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php new file mode 100644 index 00000000..6104e34f --- /dev/null +++ b/lib/composer/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 self + */ + public function ignoreHeader($header_name); + + /** + * Prepare the Signer to get a new Body. + * + * @return self + */ + public function startBody(); + + /** + * Give the signal that the body has finished streaming. + * + * @return self + */ + public function endBody(); + + /** + * Give the headers already given. + * + * @param Swift_Mime_SimpleHeaderSet $headers + * + * @return self + */ + public function setHeaders(Swift_Mime_SimpleHeaderSet $headers); + + /** + * Add the header(s) to the headerSet. + * + * @param Swift_Mime_SimpleHeaderSet $headers + * + * @return self + */ + public function addSignature(Swift_Mime_SimpleHeaderSet $headers); + + /** + * Return the list of header a signer might tamper. + * + * @return array + */ + public function getAlteredHeaders(); +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php new file mode 100644 index 00000000..deb29f57 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php @@ -0,0 +1,185 @@ + + */ +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')) { + throw new Swift_SwiftException('php-opendkim extension not found'); + } + + $this->peclLoaded = true; + + parent::__construct($privateKey, $domainName, $selector); + } + + public function addSignature(Swift_Mime_SimpleHeaderSet $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_SimpleHeaderSet $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 int $time + * + * @return $this + */ + public function setSignatureTimestamp($time) + { + $this->signatureTimestamp = $time; + + return $this; + } + + /** + * Set the signature expiration timestamp. + * + * @param int $time + * + * @return $this + */ + public function setSignatureExpiration($time) + { + $this->signatureExpiration = $time; + + return $this; + } + + /** + * Enable / disable the DebugHeaders. + * + * @param bool $debug + * + * @return $this + */ + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php new file mode 100644 index 00000000..eea2648c --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php @@ -0,0 +1,417 @@ + + */ +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; + protected $extraCerts = null; + + /** + * @var Swift_StreamFilters_StringReplacementFilterFactory + */ + protected $replacementFactory; + + /** + * @var Swift_Mime_SimpleHeaderFactory + */ + protected $headerFactory; + + /** + * Constructor. + * + * @param string|null $signCertificate + * @param string|null $signPrivateKey + * @param string|null $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; + $this->encryptCipher = OPENSSL_CIPHER_AES_128_CBC; + } + + /** + * Set the certificate location to use for signing. + * + * @see 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() + * @param string $extraCerts A file containing intermediate certificates needed by the signing certificate + * + * @return $this + */ + public function setSignCertificate($certificate, $privateKey = null, $signOptions = PKCS7_DETACHED, $extraCerts = null) + { + $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; + if (null !== $extraCerts) { + $this->extraCerts = str_replace('\\', '/', realpath($extraCerts)); + } + + return $this; + } + + /** + * Set the certificate location to use for encryption. + * + * @see http://www.php.net/manual/en/openssl.pkcs7.flags.php + * @see 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 $this + */ + 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 bool $signThenEncrypt + * + * @return $this + */ + public function setSignThenEncrypt($signThenEncrypt = true) + { + $this->signThenEncrypt = $signThenEncrypt; + + return $this; + } + + /** + * @return bool + */ + public function isSignThenEncrypt() + { + return $this->signThenEncrypt; + } + + /** + * Resets internal states. + * + * @return $this + */ + public function reset() + { + return $this; + } + + /** + * Change the Swift_Message to apply the signing. + * + * @param Swift_Message $message + * + * @return $this + */ + 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(); + + $args = array($outputStream->getPath(), $signedMessageStream->getPath(), $this->signCertificate, $this->signPrivateKey, array(), $this->signOptions); + if (null !== $this->extraCerts) { + $args[] = $this->extraCerts; + } + + if (!openssl_pkcs7_sign(...$args)) { + 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'], '"'); + + // 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php new file mode 100644 index 00000000..011c03ab --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SmtpTransport.php @@ -0,0 +1,44 @@ +createDependenciesFor('transport.smtp') + ); + + $this->setHost($host); + $this->setPort($port); + $this->setEncryption($security); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Spool.php new file mode 100644 index 00000000..9d0e8fee --- /dev/null +++ b/lib/composer/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_SimpleMessage $message The message to store + * + * @return bool Whether the operation has succeeded + */ + public function queueMessage(Swift_Mime_SimpleMessage $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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php new file mode 100644 index 00000000..f92567ba --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SpoolTransport.php @@ -0,0 +1,35 @@ + + * + * 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 + ); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilter.php new file mode 100644 index 00000000..362be2e8 --- /dev/null +++ b/lib/composer/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); + $last_size = 0; + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php new file mode 100644 index 00000000..50a63f1a --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php @@ -0,0 +1,70 @@ +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) + { + if ('' === $buffer) { + return false; + } + + $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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php new file mode 100644 index 00000000..f60f0cf8 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php new file mode 100644 index 00000000..db3d3109 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/SwiftException.php @@ -0,0 +1,29 @@ +ping()) { + * $transport->stop(); + * $transport->start(); + * } + * + * The Transport mechanism will be started, if it is not already. + * + * It is undefined if the Transport mechanism attempts to restart as long as + * the return value reflects whether the mechanism is now functional. + * + * @return bool TRUE if the transport is alive + */ + public function ping(); + + /** + * 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_SimpleMessage $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null); + + /** + * Register a plugin in the Transport. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin); +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php new file mode 100644 index 00000000..34c3323f --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php @@ -0,0 +1,507 @@ +eventDispatcher = $dispatcher; + $this->buffer = $buf; + $this->setLocalDomain($localDomain); + } + + /** + * 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 does not have a domain name, use the IP address. This will + * automatically be wrapped in square brackets as described in RFC 5321, + * section 4.1.3. + * + * @param string $domain + * + * @return $this + */ + public function setLocalDomain($domain) + { + if (substr($domain, 0, 1) !== '[') { + if (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { + $domain = '['.$domain.']'; + } elseif (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + $domain = '[IPv6:'.$domain.']'; + } + } + + $this->domain = $domain; + + return $this; + } + + /** + * Get the name of the domain Swift will identify as. + * + * If an IP address was specified, this will be returned wrapped in square + * brackets as described in RFC 5321, section 4.1.3. + * + * @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_SimpleMessage $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_SimpleMessage $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)) { + $this->throwException(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; + } + + /** + * {@inheritdoc} + */ + public function ping() + { + try { + if (!$this->isStarted()) { + $this->start(); + } + + $this->executeCommand("NOOP\r\n", array(250)); + } catch (Swift_TransportException $e) { + try { + $this->stop(); + } catch (Swift_TransportException $e) { + } + + return false; + } + + return true; + } + + /** + * 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_SimpleMessage $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_SimpleMessage $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_SimpleMessage $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_SimpleMessage $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; + } + + /** + * Destructor. + */ + public function __destruct() + { + try { + $this->stop(); + } catch (Exception $e) { + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php new file mode 100644 index 00000000..26c2d745 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php new file mode 100644 index 00000000..6ab6e333 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php new file mode 100644 index 00000000..fa5d2110 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php @@ -0,0 +1,692 @@ + + */ +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 + * + * @throws \LogicException + */ + public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password) + { + if (!function_exists('openssl_encrypt')) { + throw new LogicException('The OpenSSL extension must be enabled to use the NTLM authenticator.'); + } + + if (!function_exists('bcmul')) { + throw new LogicException('The BCMath 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) : random_bytes(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 = hex2bin(substr($responseHex, 48, 16)); + $context = hex2bin(substr($responseHex, 64, 16)); + $targetInfoH = hex2bin(substr($responseHex, 80, 16)); + $targetName = 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, + 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[] = 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); + } + + if (false !== strpos($name, '@')) { + list($user, $domain) = explode('@', $name); + + return array($domain, $user); + } + + // no domain passed + return array('', $name); + } + + /** + * 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!) + $time = number_format($time, 0, '.', ''); // save microtime to string + $time = bcadd($time, '11644473600000', 0); // add epoch time + $time = bcmul($time, 10000, 0); // 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 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 = hex2bin(str_pad($input, $bytes * 2, '00')); + } else { + $byte = str_pad($input, $bytes, "\x00"); + } + + return $byte; + } + + /** ENCRYPTION ALGORITHMS */ + + /** + * DES Encryption. + * + * @param string $value An 8-byte string + * @param string $key + * + * @return string + */ + protected function desEncrypt($value, $key) + { + return substr(openssl_encrypt($value, 'DES-ECB', $key, \OPENSSL_RAW_DATA), 0, 8); + } + + /** + * 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') ? 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); + } + + /** + * @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(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].' - '.hex2bin($data[$key]).' ||| '.$value."
\n"; + } + } + + echo '

'; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php new file mode 100644 index 00000000..43219f93 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php new file mode 100644 index 00000000..d1a4cc3d --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php @@ -0,0 +1,70 @@ + + * $transport = (new Swift_SmtpTransport('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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php new file mode 100644 index 00000000..94387f01 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php new file mode 100644 index 00000000..12a9abf8 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php new file mode 100644 index 00000000..7eb7ef33 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php @@ -0,0 +1,407 @@ + 'tcp', + 'host' => 'localhost', + 'port' => 25, + 'timeout' => 30, + 'blocking' => 1, + 'tls' => false, + 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET, + 'stream_context_options' => array(), + ); + + /** + * 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 + * @param string $localDomain + */ + public function __construct(Swift_Transport_IoBuffer $buf, array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1') + { + parent::__construct($buf, $dispatcher, $localDomain); + $this->setExtensionHandlers($extensionHandlers); + } + + /** + * Set the host to connect to. + * + * @param string $host + * + * @return $this + */ + 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 $this + */ + 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 $this + */ + 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 $this + */ + public function setEncryption($encryption) + { + $encryption = strtolower($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 stream context options. + * + * @param array $options + * + * @return $this + */ + public function setStreamOptions($options) + { + $this->params['stream_context_options'] = $options; + + return $this; + } + + /** + * Returns the stream context options. + * + * @return array + */ + public function getStreamOptions() + { + return $this->params['stream_context_options']; + } + + /** + * Sets the source IP. + * + * @param string $source + * + * @return $this + */ + 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'] ?? null; + } + + /** + * Set ESMTP extension handlers. + * + * @param Swift_Transport_EsmtpHandler[] $handlers + * + * @return $this + */ + public function setExtensionHandlers(array $handlers) + { + $assoc = array(); + foreach ($handlers as $handler) { + $assoc[$handler->getHandledKeyword()] = $handler; + } + uasort($assoc, function ($a, $b) { + return $a->getPriorityOver($b->getHandledKeyword()); + }); + $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 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 (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; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php new file mode 100644 index 00000000..94151f89 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php @@ -0,0 +1,106 @@ +transports); + for ($i = 0; $i < $maxTransports + && $transport = $this->getNextTransport(); ++$i) { + if ($transport->ping()) { + return true; + } else { + $this->killCurrentTransport(); + } + } + + return count($this->transports) > 0; + } + + /** + * 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_SimpleMessage $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) + { + $maxTransports = count($this->transports); + $sent = 0; + $this->lastUsedTransport = null; + + for ($i = 0; $i < $maxTransports + && $transport = $this->getNextTransport(); ++$i) { + try { + if (!$transport->isStarted()) { + $transport->start(); + } + + if ($sent = $transport->send($message, $failedRecipients)) { + $this->lastUsedTransport = $transport; + + return $sent; + } + } 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php new file mode 100644 index 00000000..af97adf1 --- /dev/null +++ b/lib/composer/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); + } + + /** + * Get the Transport used in the last successful send operation. + * + * @return Swift_Transport + */ + public function getLastUsedTransport() + { + return $this->lastUsedTransport; + } + + /** + * 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(); + } + } + + /** + * {@inheritdoc} + */ + public function ping() + { + foreach ($this->transports as $transport) { + if (!$transport->ping()) { + $this->killCurrentTransport(); + } + } + + return count($this->transports) > 0; + } + + /** + * 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_SimpleMessage $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) + { + $maxTransports = count($this->transports); + $sent = 0; + $this->lastUsedTransport = null; + + for ($i = 0; $i < $maxTransports + && $transport = $this->getNextTransport(); ++$i) { + try { + if (!$transport->isStarted()) { + $transport->start(); + } + if ($sent = $transport->send($message, $failedRecipients)) { + $this->lastUsedTransport = $transport; + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php new file mode 100644 index 00000000..dc38078c --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/NullTransport.php @@ -0,0 +1,101 @@ + + * + * 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() + { + } + + /** + * {@inheritdoc} + */ + public function ping() + { + return true; + } + + /** + * Sends the given message. + * + * @param Swift_Mime_SimpleMessage $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int The number of sent emails + */ + public function send(Swift_Mime_SimpleMessage $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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php new file mode 100644 index 00000000..80753850 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php @@ -0,0 +1,161 @@ + 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 + * @param string $localDomain + */ + public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1') + { + parent::__construct($buf, $dispatcher, $localDomain); + } + + /** + * 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 $this + */ + 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_SimpleMessage $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null) + { + $failedRecipients = (array) $failedRecipients; + $command = $this->getCommand(); + $buffer = $this->getBuffer(); + $count = 0; + + 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SmtpAgent.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SmtpAgent.php new file mode 100644 index 00000000..90e913f8 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/SmtpAgent.php @@ -0,0 +1,36 @@ + + * + * 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 $this + */ + 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() + { + } + + /** + * {@inheritdoc} + */ + public function ping() + { + return true; + } + + /** + * Sends the given message. + * + * @param Swift_Mime_SimpleMessage $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int The number of sent e-mail's + */ + public function send(Swift_Mime_SimpleMessage $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_SPOOLED : 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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php new file mode 100644 index 00000000..bc6ed5a3 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php @@ -0,0 +1,326 @@ +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 doCommit($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'; + } + + if (isset($this->params['stream_context_options'])) { + $options = array_merge($options, $this->params['stream_context_options']); + } + $streamContext = stream_context_create($options); + $this->stream = @stream_socket_client($host.':'.$this->params['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $streamContext); + 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'), + ); + $pipes = array(); + $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/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php new file mode 100644 index 00000000..4ae2412e --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/classes/Swift/TransportException.php @@ -0,0 +1,29 @@ +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/lib/composer/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/dependency_maps/message_deps.php new file mode 100644 index 00000000..64d69d21 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php new file mode 100644 index 00000000..4ce9c7cb --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/dependency_maps/mime_deps.php @@ -0,0 +1,130 @@ +register('properties.charset') + ->asValue('utf-8') + + ->register('email.validator') + ->asSharedInstanceOf('Egulias\EmailValidator\EmailValidator') + + ->register('mime.idgenerator.idright') + // As SERVER_NAME can come from the user in certain configurations, check that + // it does not contain forbidden characters (see RFC 952 and RFC 2181). Use + // preg_replace() instead of preg_match() to prevent DoS attacks with long host names. + ->asValue(!empty($_SERVER['SERVER_NAME']) && preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $_SERVER['SERVER_NAME']) === '' ? $_SERVER['SERVER_NAME'] : 'swift.generated') + + ->register('mime.idgenerator') + ->asSharedInstanceOf('Swift_Mime_IdGenerator') + ->withDependencies(array( + 'mime.idgenerator.idright', + )) + + ->register('mime.message') + ->asNewInstanceOf('Swift_Mime_SimpleMessage') + ->withDependencies(array( + 'mime.headerset', + 'mime.qpcontentencoder', + 'cache', + 'mime.idgenerator', + 'properties.charset', + )) + + ->register('mime.part') + ->asNewInstanceOf('Swift_Mime_MimePart') + ->withDependencies(array( + 'mime.headerset', + 'mime.qpcontentencoder', + 'cache', + 'mime.idgenerator', + 'properties.charset', + )) + + ->register('mime.attachment') + ->asNewInstanceOf('Swift_Mime_Attachment') + ->withDependencies(array( + 'mime.headerset', + 'mime.base64contentencoder', + 'cache', + 'mime.idgenerator', + )) + ->addConstructorValue($swift_mime_types) + + ->register('mime.embeddedfile') + ->asNewInstanceOf('Swift_Mime_EmbeddedFile') + ->withDependencies(array( + 'mime.headerset', + 'mime.base64contentencoder', + 'cache', + 'mime.idgenerator', + )) + ->addConstructorValue($swift_mime_types) + + ->register('mime.headerfactory') + ->asNewInstanceOf('Swift_Mime_SimpleHeaderFactory') + ->withDependencies(array( + 'mime.qpheaderencoder', + 'mime.rfc2231encoder', + 'email.validator', + '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.qpcontentencoder') + ->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')) +; + +unset($swift_mime_types); diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php new file mode 100644 index 00000000..15772abb --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/dependency_maps/transport_deps.php @@ -0,0 +1,77 @@ +register('transport.localdomain') + // As SERVER_NAME can come from the user in certain configurations, check that + // it does not contain forbidden characters (see RFC 952 and RFC 2181). Use + // preg_replace() instead of preg_match() to prevent DoS attacks with long host names. + ->asValue(!empty($_SERVER['SERVER_NAME']) && preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $_SERVER['SERVER_NAME']) === '' ? trim($_SERVER['SERVER_NAME'], '[]') : '127.0.0.1') + + ->register('transport.smtp') + ->asNewInstanceOf('Swift_Transport_EsmtpTransport') + ->withDependencies(array( + 'transport.buffer', + array('transport.authhandler'), + 'transport.eventdispatcher', + 'transport.localdomain', + )) + + ->register('transport.sendmail') + ->asNewInstanceOf('Swift_Transport_SendmailTransport') + ->withDependencies(array( + 'transport.buffer', + 'transport.eventdispatcher', + 'transport.localdomain', + )) + + ->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.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/lib/composer/vendor/swiftmailer/swiftmailer/lib/mime_types.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/mime_types.php new file mode 100644 index 00000000..b42c1cc1 --- /dev/null +++ b/lib/composer/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/lib/composer/vendor/swiftmailer/swiftmailer/lib/preferences.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/preferences.php new file mode 100644 index 00000000..27b7065d --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/preferences.php @@ -0,0 +1,19 @@ +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'); +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/lib/swift_required.php b/lib/composer/vendor/swiftmailer/swiftmailer/lib/swift_required.php new file mode 100644 index 00000000..d696056a --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/lib/swift_required.php @@ -0,0 +1,22 @@ + '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', + '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/vnd.ms-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/lib/composer/vendor/swiftmailer/swiftmailer/phpunit.xml.dist b/lib/composer/vendor/swiftmailer/swiftmailer/phpunit.xml.dist new file mode 100644 index 00000000..9ec0c49a --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/phpunit.xml.dist @@ -0,0 +1,38 @@ + + + + + + + + + + + + tests/unit + + + tests/acceptance + + + tests/bug + + + tests/smoke + + + + + + + diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/IdenticalBinaryConstraint.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/IdenticalBinaryConstraint.php new file mode 100644 index 00000000..0a4a6da8 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/IdenticalBinaryConstraint.php @@ -0,0 +1,62 @@ +value = $value; + } + + /** + * Evaluates the constraint for parameter $other. Returns TRUE if the + * constraint is met, FALSE otherwise. + * + * @param mixed $other Value or object to evaluate. + * + * @return bool + */ + public function matches($other) + { + $aHex = $this->asHexString($this->value); + $bHex = $this->asHexString($other); + + return $aHex === $bHex; + } + + /** + * Returns a string representation of the constraint. + * + * @return string + */ + public function toString() + { + return 'identical binary'; + } + + /** + * Get the given string of bytes as a stirng of Hexadecimal sequences. + * + * @param string $binary + * + * @return string + */ + private function asHexString($binary) + { + $hex = ''; + + $bytes = unpack('H*', $binary); + + foreach ($bytes as &$byte) { + $byte = strtoupper($byte); + } + + return implode('', $bytes); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/StreamCollector.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/StreamCollector.php new file mode 100644 index 00000000..7f079d98 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/StreamCollector.php @@ -0,0 +1,11 @@ +content .= $arg; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/SwiftMailerSmokeTestCase.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/SwiftMailerSmokeTestCase.php new file mode 100644 index 00000000..13bd2403 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/SwiftMailerSmokeTestCase.php @@ -0,0 +1,46 @@ +markTestSkipped( + 'Smoke tests are skipped if tests/smoke.conf.php is not edited' + ); + } + } + + protected function getMailer() + { + switch (SWIFT_SMOKE_TRANSPORT_TYPE) { + case 'smtp': + $transport = Swift_DependencyContainer::getInstance()->lookup('transport.smtp') + ->setHost(SWIFT_SMOKE_SMTP_HOST) + ->setPort(SWIFT_SMOKE_SMTP_PORT) + ->setUsername(SWIFT_SMOKE_SMTP_USER) + ->setPassword(SWIFT_SMOKE_SMTP_PASS) + ->setEncryption(SWIFT_SMOKE_SMTP_ENCRYPTION) + ; + break; + case 'sendmail': + $transport = Swift_DependencyContainer::getInstance()->lookup('transport.sendmail') + ->setCommand(SWIFT_SMOKE_SENDMAIL_COMMAND) + ; + break; + case 'mail': + case 'nativemail': + $transport = Swift_DependencyContainer::getInstance()->lookup('transport.mail'); + break; + default: + throw new Exception('Undefined transport ['.SWIFT_SMOKE_TRANSPORT_TYPE.']'); + } + + return new Swift_Mailer($transport); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/SwiftMailerTestCase.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/SwiftMailerTestCase.php new file mode 100644 index 00000000..fe2c62b4 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/SwiftMailerTestCase.php @@ -0,0 +1,38 @@ + \ No newline at end of file diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/files/swiftmailer.png b/lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/files/swiftmailer.png new file mode 100644 index 0000000000000000000000000000000000000000..1b95f619af1fcbed1fca382d22022bdf329849cf GIT binary patch literal 3194 zcmV-=42AQFP)MSx|GoLxC1$NK z_Ph69ufRtQ76+DFuvF-8orSRY^mzh{hyTC*`g`GJF2^N{QXxQY!g418;53Gy4`6Wt z@W4WCEiaf6;7tNLOGCi-2=LHCZ7mC!tMIWuL$7RVA;G=7=x|%8^OYGLShnYUDhm&{ zg*qRgG59-xrCOlVLap5bussX4wX{GtNp2L?&||kP)YeRa-p?TroQ0vc-dGelVxhJ` zbHgmj`XYe6V)0vOpab&4Cj>2rw?=>CC(n=L-$$^lSx;?E2D-=Qo8dr^dBcluc+ORJ zo@Ok)#uf8ieAG%L42Q#c`YOud`3-#p& zx0pwR}3v$0N&KqF{v0Ir|mG1_!JrIaAnQ_n_r40Af1%SNq$VGh?- zDXXWpP)~pJk68AdlR|>owIyz$&Kl?@%RbwIX}OKd*e}{@>J;|jNB^t|SqlG$KX_@< zYPOT{srCWpmc{fEdFtc$hkWQ00_xRYTk~Q-#%(ZN)nMakx2TCY4cs|+=~l+UpzgXH z3KFBCVsZn{{@|S|8)bT`V)?Z;Zx^N|a=FAncPT*Yk;goObw@Ek5$~cJb)e&uswQUhp?_8ZB}LDU1)1XVxzQBgVh!5bYS*aa$n|JikshH+4PM@px5US z5KI1hj^xpt1p^u_NV(oZoq@I4d3Q?gY1@Xf0y7?wX2swT7EcHglRVbe z0s_q_WwNWG>Pu4vf1~O-k3Mg0@!VhV^|zdz4O~YIj}5@ z)|!D$l=1lH%JrgXWP>a>qy`4 zfd_Xf*yB0msv=VnO421sgGW<)JvhBrJALv+<+Cq+cK6}C5v;E~_vYC~kG{Uo{Le>+ zz5eve?B>-s*bC2G&c>a(FWeJ{VvUPW=jQFDIEYEMIT|^L*`CApFW>5Gpxq`exeb89 zK7rhmuDQL!NoS)W{BchYPx)ZMZO}SZReVg^Oa`>3+8)*qpg=su`iAD=;tzrDdzX&m zBt-gYJVkUPuC3gN{#jlARs{76&#bZQS6)8f>I#dXe&yLW+0E5AlsiJm3G|b<*-N~2 zQ#XAApDW}JY&X_81Ta_V;cXaP170tBZ-i?d;8r~(n~HKdiE#iXUU^&Ld}NF6C2Whw z-vGGfa~qqI4Vd+ry8rqeEX!*GX zPzuPkInk36ZVgpFze_+8TWRTeWKV;P8V#8kOEY&5b$_oN=C zfVZ9!c1KeSWEKdT+UKXAXurGQxsz=>%?&57Zc?TJIUHR%WUjYKGjD6|O`mFWU-Qsy z8$ex&%YLW|W*0O|TXOeRszyS|bM{oy0VIWM2yYGh6Now-{;$MnFB9tv7p>Bn0mTPK z!QiJ~e83)pUOtEVUq&Z^zk2`=z%|g`FMi`kNt*|xpDPM&E!L90^pHD3t%<+)L}>x= zHZ-2OF^#M+sfjfAr7g+}fWNCK^DS7vtB@f&qSp+K@c*Z;;KpqHsmIns`02nB4 zKwSio^mHYm+UaW~&e@6U0#MmVdv+-Z>#CrJZMv%8!uDfOe*$nqU}t{`TMB zU-0PvdvY3n|LTu*WzdK7X$j|mWieEgSzQ4MV=|V}Au&KJv7|%P<1?LGi1~iu+Cz>4&0c?*B=<+n4#;eO3s47W{ zB(KnrY5~Xa!V72jAAhXU+^x4>?YbX+^mElu_Obwx(tOI-?@m=iD#6~&JN?i2qW>RG*IxzvC z%KL6Ag*@E5P1w+3EWTGe$UjqK^=XXgpk4UJ66dz_(44`X-J*wOdY zC3PE?sU85{Opeu46To)qgaW}McTAwBbX>sVJLeoLAdicbjaw0CU|8T4Yz>qR`*Zx{ z+j~*|8UM!5zy9YpMF>P?YXZdggn*yNM!9B0Ks$Q?rb>=BDOWvU=S|x+dKevHdv6+N zwxXyaOr8>5gMrK9JEM4tCpyjcS$XLuzi#aBtm>469-6Pme$)jpWxpG8LPf}kplnsm zF<8y|{FYhzd|-=GfF_<;r>D7h_Y#gj$N}i82*;<7K8QN|$63<%c^Ed4vvfnRa+O8k zt$hMJcR7Yox0kQ|+vLDli0e4wKui0mXP$0f{gmtdgjU3G+I6I(FJyO6e*FExA7i_h ze)i??Y}=IZgekTUlC}k~cMZTn$FZiU&cg{G2IFg>kt}O0x&1?~f!b4)+h{l!M*UB| zTCG3+$Ip%xItYL4#dzm&aXQ|L7~9OP>cyuT4WkKyD#A@x{zjTR4?7HbbltHp9Ks=4 zvJ^p}1>jph{m!3#)xI_7A$O?_sPhstId7(!_m4)vIEs7c(g0t@$jUKGD|Z1+@@7 z?vvLG$!qTxG$6#j9L))L;gN?9EglOFwWc~p0NO?IXhII!W;iU=sXd`Qp=6(c2<8Mc zA2&H^qfx*Vb46RbBv1<=b=i2o*xcbJ?VM(2P1$mL-?z1bLrp+Aq_e9ExCdEzKJv^6 z^VSqn!+K{6^+Z*FK%Q_g3*Ak@Du2_#q@MX~c7E%fEz~AnyTkNT_J$N#p3r9yCsXKQ z;jeeQ#bz`6&|I~@wUR+CY1~dqSs+S)Earl*U32337r@fWm`K g-$HCnw*Lz-0AR%yng8k!ga7~l07*qoM6N<$f>^s2o&W#< literal 0 HcmV?d00001 diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/files/textfile.zip b/lib/composer/vendor/swiftmailer/swiftmailer/tests/_samples/files/textfile.zip new file mode 100644 index 0000000000000000000000000000000000000000..5a580ecbf81ff98445bc5c6d0fce7a9a301f0e39 GIT binary patch literal 202 zcmWIWW@h1HU}9ikII%0tqR&rhgC39#!aNM33?-=*C25&Csd^<9C7~gl49w;G_PK*_ zXax(ySH`c5AsLy)3P4nlSX82rpQezg5L}*_R-)jW2-H=iP-db~oSUDWs!)testFile = sys_get_temp_dir().'/swift-test-file'.__CLASS__; + file_put_contents($this->testFile, 'abcdefghijklm'); + } + + protected function tearDown() + { + unlink($this->testFile); + } + + public function testFileDataCanBeRead() + { + $file = $this->createFileStream($this->testFile); + $str = ''; + while (false !== $bytes = $file->read(8192)) { + $str .= $bytes; + } + $this->assertEquals('abcdefghijklm', $str); + } + + public function testFileDataCanBeReadSequentially() + { + $file = $this->createFileStream($this->testFile); + $this->assertEquals('abcde', $file->read(5)); + $this->assertEquals('fghijklm', $file->read(8)); + $this->assertFalse($file->read(1)); + } + + public function testFilenameIsReturned() + { + $file = $this->createFileStream($this->testFile); + $this->assertEquals($this->testFile, $file->getPath()); + } + + public function testFileCanBeWrittenTo() + { + $file = $this->createFileStream($this->testFile, true); + $file->write('foobar'); + $this->assertEquals('foobar', $file->read(8192)); + } + + public function testReadingFromThenWritingToFile() + { + $file = $this->createFileStream($this->testFile, true); + $file->write('foobar'); + $this->assertEquals('foobar', $file->read(8192)); + $file->write('zipbutton'); + $this->assertEquals('zipbutton', $file->read(8192)); + } + + public function testWritingToFileWithCanonicalization() + { + $file = $this->createFileStream($this->testFile, true); + $file->addFilter($this->createFilter(array("\r\n", "\r"), "\n"), 'allToLF'); + $file->write("foo\r\nbar\r"); + $file->write("\nzip\r\ntest\r"); + $file->flushBuffers(); + $this->assertEquals("foo\nbar\nzip\ntest\n", file_get_contents($this->testFile)); + } + + public function testWritingWithFulleMessageLengthOfAMultipleOf8192() + { + $file = $this->createFileStream($this->testFile, true); + $file->addFilter($this->createFilter(array("\r\n", "\r"), "\n"), 'allToLF'); + $file->write(''); + $file->flushBuffers(); + $this->assertEquals('', file_get_contents($this->testFile)); + } + + public function testBindingOtherStreamsMirrorsWriteOperations() + { + $file = $this->createFileStream($this->testFile, true); + $is1 = $this->createMockInputStream(); + $is2 = $this->createMockInputStream(); + + $is1->expects($this->at(0)) + ->method('write') + ->with('x'); + $is1->expects($this->at(1)) + ->method('write') + ->with('y'); + $is2->expects($this->at(0)) + ->method('write') + ->with('x'); + $is2->expects($this->at(1)) + ->method('write') + ->with('y'); + + $file->bind($is1); + $file->bind($is2); + + $file->write('x'); + $file->write('y'); + } + + public function testBindingOtherStreamsMirrorsFlushOperations() + { + $file = $this->createFileStream( + $this->testFile, true + ); + $is1 = $this->createMockInputStream(); + $is2 = $this->createMockInputStream(); + + $is1->expects($this->once()) + ->method('flushBuffers'); + $is2->expects($this->once()) + ->method('flushBuffers'); + + $file->bind($is1); + $file->bind($is2); + + $file->flushBuffers(); + } + + public function testUnbindingStreamPreventsFurtherWrites() + { + $file = $this->createFileStream($this->testFile, true); + $is1 = $this->createMockInputStream(); + $is2 = $this->createMockInputStream(); + + $is1->expects($this->at(0)) + ->method('write') + ->with('x'); + $is1->expects($this->at(1)) + ->method('write') + ->with('y'); + $is2->expects($this->once()) + ->method('write') + ->with('x'); + + $file->bind($is1); + $file->bind($is2); + + $file->write('x'); + + $file->unbind($is2); + + $file->write('y'); + } + + private function createFilter($search, $replace) + { + return new Swift_StreamFilters_StringReplacementFilter($search, $replace); + } + + private function createMockInputStream() + { + return $this->getMockBuilder('Swift_InputByteStream')->getMock(); + } + + private function createFileStream($file, $writable = false) + { + return new Swift_ByteStream_FileByteStream($file, $writable); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/CharacterReaderFactory/SimpleCharacterReaderFactoryAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/CharacterReaderFactory/SimpleCharacterReaderFactoryAcceptanceTest.php new file mode 100644 index 00000000..6b3c48e8 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/CharacterReaderFactory/SimpleCharacterReaderFactoryAcceptanceTest.php @@ -0,0 +1,179 @@ +factory = new Swift_CharacterReaderFactory_SimpleCharacterReaderFactory(); + } + + public function testCreatingUtf8Reader() + { + foreach (array('utf8', 'utf-8', 'UTF-8', 'UTF8') as $utf8) { + $reader = $this->factory->getReaderFor($utf8); + $this->assertInstanceOf($this->prefix.'Utf8Reader', $reader); + } + } + + public function testCreatingIso8859XReaders() + { + $charsets = array(); + foreach (range(1, 16) as $number) { + foreach (array('iso', 'iec') as $body) { + $charsets[] = $body.'-8859-'.$number; + $charsets[] = $body.'8859-'.$number; + $charsets[] = strtoupper($body).'-8859-'.$number; + $charsets[] = strtoupper($body).'8859-'.$number; + } + } + + foreach ($charsets as $charset) { + $reader = $this->factory->getReaderFor($charset); + $this->assertInstanceOf($this->prefix.'GenericFixedWidthReader', $reader); + $this->assertEquals(1, $reader->getInitialByteSize()); + } + } + + public function testCreatingWindows125XReaders() + { + $charsets = array(); + foreach (range(0, 8) as $number) { + $charsets[] = 'windows-125'.$number; + $charsets[] = 'windows125'.$number; + $charsets[] = 'WINDOWS-125'.$number; + $charsets[] = 'WINDOWS125'.$number; + } + + foreach ($charsets as $charset) { + $reader = $this->factory->getReaderFor($charset); + $this->assertInstanceOf($this->prefix.'GenericFixedWidthReader', $reader); + $this->assertEquals(1, $reader->getInitialByteSize()); + } + } + + public function testCreatingCodePageReaders() + { + $charsets = array(); + foreach (range(0, 8) as $number) { + $charsets[] = 'cp-125'.$number; + $charsets[] = 'cp125'.$number; + $charsets[] = 'CP-125'.$number; + $charsets[] = 'CP125'.$number; + } + + foreach (array(437, 737, 850, 855, 857, 858, 860, + 861, 863, 865, 866, 869, ) as $number) { + $charsets[] = 'cp-'.$number; + $charsets[] = 'cp'.$number; + $charsets[] = 'CP-'.$number; + $charsets[] = 'CP'.$number; + } + + foreach ($charsets as $charset) { + $reader = $this->factory->getReaderFor($charset); + $this->assertInstanceOf($this->prefix.'GenericFixedWidthReader', $reader); + $this->assertEquals(1, $reader->getInitialByteSize()); + } + } + + public function testCreatingAnsiReader() + { + foreach (array('ansi', 'ANSI') as $ansi) { + $reader = $this->factory->getReaderFor($ansi); + $this->assertInstanceOf($this->prefix.'GenericFixedWidthReader', $reader); + $this->assertEquals(1, $reader->getInitialByteSize()); + } + } + + public function testCreatingMacintoshReader() + { + foreach (array('macintosh', 'MACINTOSH') as $mac) { + $reader = $this->factory->getReaderFor($mac); + $this->assertInstanceOf($this->prefix.'GenericFixedWidthReader', $reader); + $this->assertEquals(1, $reader->getInitialByteSize()); + } + } + + public function testCreatingKOIReaders() + { + $charsets = array(); + foreach (array('7', '8-r', '8-u', '8u', '8r') as $end) { + $charsets[] = 'koi-'.$end; + $charsets[] = 'koi'.$end; + $charsets[] = 'KOI-'.$end; + $charsets[] = 'KOI'.$end; + } + + foreach ($charsets as $charset) { + $reader = $this->factory->getReaderFor($charset); + $this->assertInstanceOf($this->prefix.'GenericFixedWidthReader', $reader); + $this->assertEquals(1, $reader->getInitialByteSize()); + } + } + + public function testCreatingIsciiReaders() + { + foreach (array('iscii', 'ISCII', 'viscii', 'VISCII') as $charset) { + $reader = $this->factory->getReaderFor($charset); + $this->assertInstanceOf($this->prefix.'GenericFixedWidthReader', $reader); + $this->assertEquals(1, $reader->getInitialByteSize()); + } + } + + public function testCreatingMIKReader() + { + foreach (array('mik', 'MIK') as $charset) { + $reader = $this->factory->getReaderFor($charset); + $this->assertInstanceOf($this->prefix.'GenericFixedWidthReader', $reader); + $this->assertEquals(1, $reader->getInitialByteSize()); + } + } + + public function testCreatingCorkReader() + { + foreach (array('cork', 'CORK', 't1', 'T1') as $charset) { + $reader = $this->factory->getReaderFor($charset); + $this->assertInstanceOf($this->prefix.'GenericFixedWidthReader', $reader); + $this->assertEquals(1, $reader->getInitialByteSize()); + } + } + + public function testCreatingUcs2Reader() + { + foreach (array('ucs-2', 'UCS-2', 'ucs2', 'UCS2') as $charset) { + $reader = $this->factory->getReaderFor($charset); + $this->assertInstanceOf($this->prefix.'GenericFixedWidthReader', $reader); + $this->assertEquals(2, $reader->getInitialByteSize()); + } + } + + public function testCreatingUtf16Reader() + { + foreach (array('utf-16', 'UTF-16', 'utf16', 'UTF16') as $charset) { + $reader = $this->factory->getReaderFor($charset); + $this->assertInstanceOf($this->prefix.'GenericFixedWidthReader', $reader); + $this->assertEquals(2, $reader->getInitialByteSize()); + } + } + + public function testCreatingUcs4Reader() + { + foreach (array('ucs-4', 'UCS-4', 'ucs4', 'UCS4') as $charset) { + $reader = $this->factory->getReaderFor($charset); + $this->assertInstanceOf($this->prefix.'GenericFixedWidthReader', $reader); + $this->assertEquals(4, $reader->getInitialByteSize()); + } + } + + public function testCreatingUtf32Reader() + { + foreach (array('utf-32', 'UTF-32', 'utf32', 'UTF32') as $charset) { + $reader = $this->factory->getReaderFor($charset); + $this->assertInstanceOf($this->prefix.'GenericFixedWidthReader', $reader); + $this->assertEquals(4, $reader->getInitialByteSize()); + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/DependencyContainerAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/DependencyContainerAcceptanceTest.php new file mode 100644 index 00000000..3c1b515b --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/DependencyContainerAcceptanceTest.php @@ -0,0 +1,22 @@ +listItems() as $itemName) { + try { + $di->lookup($itemName); + } catch (Swift_DependencyException $e) { + $this->fail($e->getMessage()); + } + } + // previous loop would fail if there is an issue + $this->addToAssertionCount(1); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/EmbeddedFileAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/EmbeddedFileAcceptanceTest.php new file mode 100644 index 00000000..a172e972 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/EmbeddedFileAcceptanceTest.php @@ -0,0 +1,12 @@ +samplesDir = realpath(__DIR__.'/../../../_samples/charsets'); + $this->encoder = new Swift_Encoder_Base64Encoder(); + } + + public function testEncodingAndDecodingSamples() + { + $sampleFp = opendir($this->samplesDir); + while (false !== $encodingDir = readdir($sampleFp)) { + if (substr($encodingDir, 0, 1) == '.') { + continue; + } + + $sampleDir = $this->samplesDir.'/'.$encodingDir; + + if (is_dir($sampleDir)) { + $fileFp = opendir($sampleDir); + while (false !== $sampleFile = readdir($fileFp)) { + if (substr($sampleFile, 0, 1) == '.') { + continue; + } + + $text = file_get_contents($sampleDir.'/'.$sampleFile); + $encodedText = $this->encoder->encodeString($text); + + $this->assertEquals( + base64_decode($encodedText), $text, + '%s: Encoded string should decode back to original string for sample '. + $sampleDir.'/'.$sampleFile + ); + } + closedir($fileFp); + } + } + closedir($sampleFp); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Encoder/QpEncoderAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Encoder/QpEncoderAcceptanceTest.php new file mode 100644 index 00000000..f2af26b9 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Encoder/QpEncoderAcceptanceTest.php @@ -0,0 +1,54 @@ +samplesDir = realpath(__DIR__.'/../../../_samples/charsets'); + $this->factory = new Swift_CharacterReaderFactory_SimpleCharacterReaderFactory(); + } + + public function testEncodingAndDecodingSamples() + { + $sampleFp = opendir($this->samplesDir); + while (false !== $encodingDir = readdir($sampleFp)) { + if (substr($encodingDir, 0, 1) == '.') { + continue; + } + + $encoding = $encodingDir; + $charStream = new Swift_CharacterStream_ArrayCharacterStream( + $this->factory, $encoding); + $encoder = new Swift_Encoder_QpEncoder($charStream); + + $sampleDir = $this->samplesDir.'/'.$encodingDir; + + if (is_dir($sampleDir)) { + $fileFp = opendir($sampleDir); + while (false !== $sampleFile = readdir($fileFp)) { + if (substr($sampleFile, 0, 1) == '.') { + continue; + } + + $text = file_get_contents($sampleDir.'/'.$sampleFile); + $encodedText = $encoder->encodeString($text); + + foreach (explode("\r\n", $encodedText) as $line) { + $this->assertLessThanOrEqual(76, strlen($line)); + } + + $this->assertEquals( + quoted_printable_decode($encodedText), $text, + '%s: Encoded string should decode back to original string for sample '. + $sampleDir.'/'.$sampleFile + ); + } + closedir($fileFp); + } + } + closedir($sampleFp); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Encoder/Rfc2231EncoderAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Encoder/Rfc2231EncoderAcceptanceTest.php new file mode 100644 index 00000000..f31ac5bd --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Encoder/Rfc2231EncoderAcceptanceTest.php @@ -0,0 +1,50 @@ +samplesDir = realpath(__DIR__.'/../../../_samples/charsets'); + $this->factory = new Swift_CharacterReaderFactory_SimpleCharacterReaderFactory(); + } + + public function testEncodingAndDecodingSamples() + { + $sampleFp = opendir($this->samplesDir); + while (false !== $encodingDir = readdir($sampleFp)) { + if (substr($encodingDir, 0, 1) == '.') { + continue; + } + + $encoding = $encodingDir; + $charStream = new Swift_CharacterStream_ArrayCharacterStream( + $this->factory, $encoding); + $encoder = new Swift_Encoder_Rfc2231Encoder($charStream); + + $sampleDir = $this->samplesDir.'/'.$encodingDir; + + if (is_dir($sampleDir)) { + $fileFp = opendir($sampleDir); + while (false !== $sampleFile = readdir($fileFp)) { + if (substr($sampleFile, 0, 1) == '.') { + continue; + } + + $text = file_get_contents($sampleDir.'/'.$sampleFile); + $encodedText = $encoder->encodeString($text); + + $this->assertEquals( + urldecode(implode('', explode("\r\n", $encodedText))), $text, + '%s: Encoded string should decode back to original string for sample '. + $sampleDir.'/'.$sampleFile + ); + } + closedir($fileFp); + } + } + closedir($sampleFp); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/KeyCache/ArrayKeyCacheAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/KeyCache/ArrayKeyCacheAcceptanceTest.php new file mode 100644 index 00000000..c54986b2 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/KeyCache/ArrayKeyCacheAcceptanceTest.php @@ -0,0 +1,173 @@ +cache = new Swift_KeyCache_ArrayKeyCache( + new Swift_KeyCache_SimpleKeyCacheInputStream() + ); + } + + public function testStringDataCanBeSetAndFetched() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->assertEquals('test', $this->cache->getString($this->key1, 'foo')); + } + + public function testStringDataCanBeOverwritten() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->cache->setString( + $this->key1, 'foo', 'whatever', Swift_KeyCache::MODE_WRITE + ); + $this->assertEquals('whatever', $this->cache->getString($this->key1, 'foo')); + } + + public function testStringDataCanBeAppended() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->cache->setString( + $this->key1, 'foo', 'ing', Swift_KeyCache::MODE_APPEND + ); + $this->assertEquals('testing', $this->cache->getString($this->key1, 'foo')); + } + + public function testHasKeyReturnValue() + { + $this->assertFalse($this->cache->hasKey($this->key1, 'foo')); + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->assertTrue($this->cache->hasKey($this->key1, 'foo')); + } + + public function testNsKeyIsWellPartitioned() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->cache->setString( + $this->key2, 'foo', 'ing', Swift_KeyCache::MODE_WRITE + ); + $this->assertEquals('test', $this->cache->getString($this->key1, 'foo')); + $this->assertEquals('ing', $this->cache->getString($this->key2, 'foo')); + } + + public function testItemKeyIsWellPartitioned() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->cache->setString( + $this->key1, 'bar', 'ing', Swift_KeyCache::MODE_WRITE + ); + $this->assertEquals('test', $this->cache->getString($this->key1, 'foo')); + $this->assertEquals('ing', $this->cache->getString($this->key1, 'bar')); + } + + public function testByteStreamCanBeImported() + { + $os = new Swift_ByteStream_ArrayByteStream(); + $os->write('abcdef'); + + $this->cache->importFromByteStream( + $this->key1, 'foo', $os, Swift_KeyCache::MODE_WRITE + ); + $this->assertEquals('abcdef', $this->cache->getString($this->key1, 'foo')); + } + + public function testByteStreamCanBeAppended() + { + $os1 = new Swift_ByteStream_ArrayByteStream(); + $os1->write('abcdef'); + + $os2 = new Swift_ByteStream_ArrayByteStream(); + $os2->write('xyzuvw'); + + $this->cache->importFromByteStream( + $this->key1, 'foo', $os1, Swift_KeyCache::MODE_APPEND + ); + $this->cache->importFromByteStream( + $this->key1, 'foo', $os2, Swift_KeyCache::MODE_APPEND + ); + + $this->assertEquals('abcdefxyzuvw', $this->cache->getString($this->key1, 'foo')); + } + + public function testByteStreamAndStringCanBeAppended() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_APPEND + ); + + $os = new Swift_ByteStream_ArrayByteStream(); + $os->write('abcdef'); + + $this->cache->importFromByteStream( + $this->key1, 'foo', $os, Swift_KeyCache::MODE_APPEND + ); + $this->assertEquals('testabcdef', $this->cache->getString($this->key1, 'foo')); + } + + public function testDataCanBeExportedToByteStream() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + + $is = new Swift_ByteStream_ArrayByteStream(); + + $this->cache->exportToByteStream($this->key1, 'foo', $is); + + $string = ''; + while (false !== $bytes = $is->read(8192)) { + $string .= $bytes; + } + + $this->assertEquals('test', $string); + } + + public function testKeyCanBeCleared() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->assertTrue($this->cache->hasKey($this->key1, 'foo')); + $this->cache->clearKey($this->key1, 'foo'); + $this->assertFalse($this->cache->hasKey($this->key1, 'foo')); + } + + public function testNsKeyCanBeCleared() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->cache->setString( + $this->key1, 'bar', 'xyz', Swift_KeyCache::MODE_WRITE + ); + $this->assertTrue($this->cache->hasKey($this->key1, 'foo')); + $this->assertTrue($this->cache->hasKey($this->key1, 'bar')); + $this->cache->clearAll($this->key1); + $this->assertFalse($this->cache->hasKey($this->key1, 'foo')); + $this->assertFalse($this->cache->hasKey($this->key1, 'bar')); + } + + public function testKeyCacheInputStream() + { + $is = $this->cache->getInputByteStream($this->key1, 'foo'); + $is->write('abc'); + $is->write('xyz'); + $this->assertEquals('abcxyz', $this->cache->getString($this->key1, 'foo')); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/KeyCache/DiskKeyCacheAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/KeyCache/DiskKeyCacheAcceptanceTest.php new file mode 100644 index 00000000..97647423 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/KeyCache/DiskKeyCacheAcceptanceTest.php @@ -0,0 +1,173 @@ +key1 = uniqid(microtime(true), true); + $this->key2 = uniqid(microtime(true), true); + $this->cache = new Swift_KeyCache_DiskKeyCache(new Swift_KeyCache_SimpleKeyCacheInputStream(), sys_get_temp_dir()); + } + + public function testStringDataCanBeSetAndFetched() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->assertEquals('test', $this->cache->getString($this->key1, 'foo')); + } + + public function testStringDataCanBeOverwritten() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->cache->setString( + $this->key1, 'foo', 'whatever', Swift_KeyCache::MODE_WRITE + ); + $this->assertEquals('whatever', $this->cache->getString($this->key1, 'foo')); + } + + public function testStringDataCanBeAppended() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->cache->setString( + $this->key1, 'foo', 'ing', Swift_KeyCache::MODE_APPEND + ); + $this->assertEquals('testing', $this->cache->getString($this->key1, 'foo')); + } + + public function testHasKeyReturnValue() + { + $this->assertFalse($this->cache->hasKey($this->key1, 'foo')); + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->assertTrue($this->cache->hasKey($this->key1, 'foo')); + } + + public function testNsKeyIsWellPartitioned() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->cache->setString( + $this->key2, 'foo', 'ing', Swift_KeyCache::MODE_WRITE + ); + $this->assertEquals('test', $this->cache->getString($this->key1, 'foo')); + $this->assertEquals('ing', $this->cache->getString($this->key2, 'foo')); + } + + public function testItemKeyIsWellPartitioned() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->cache->setString( + $this->key1, 'bar', 'ing', Swift_KeyCache::MODE_WRITE + ); + $this->assertEquals('test', $this->cache->getString($this->key1, 'foo')); + $this->assertEquals('ing', $this->cache->getString($this->key1, 'bar')); + } + + public function testByteStreamCanBeImported() + { + $os = new Swift_ByteStream_ArrayByteStream(); + $os->write('abcdef'); + + $this->cache->importFromByteStream( + $this->key1, 'foo', $os, Swift_KeyCache::MODE_WRITE + ); + $this->assertEquals('abcdef', $this->cache->getString($this->key1, 'foo')); + } + + public function testByteStreamCanBeAppended() + { + $os1 = new Swift_ByteStream_ArrayByteStream(); + $os1->write('abcdef'); + + $os2 = new Swift_ByteStream_ArrayByteStream(); + $os2->write('xyzuvw'); + + $this->cache->importFromByteStream( + $this->key1, 'foo', $os1, Swift_KeyCache::MODE_APPEND + ); + $this->cache->importFromByteStream( + $this->key1, 'foo', $os2, Swift_KeyCache::MODE_APPEND + ); + + $this->assertEquals('abcdefxyzuvw', $this->cache->getString($this->key1, 'foo')); + } + + public function testByteStreamAndStringCanBeAppended() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_APPEND + ); + + $os = new Swift_ByteStream_ArrayByteStream(); + $os->write('abcdef'); + + $this->cache->importFromByteStream( + $this->key1, 'foo', $os, Swift_KeyCache::MODE_APPEND + ); + $this->assertEquals('testabcdef', $this->cache->getString($this->key1, 'foo')); + } + + public function testDataCanBeExportedToByteStream() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + + $is = new Swift_ByteStream_ArrayByteStream(); + + $this->cache->exportToByteStream($this->key1, 'foo', $is); + + $string = ''; + while (false !== $bytes = $is->read(8192)) { + $string .= $bytes; + } + + $this->assertEquals('test', $string); + } + + public function testKeyCanBeCleared() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->assertTrue($this->cache->hasKey($this->key1, 'foo')); + $this->cache->clearKey($this->key1, 'foo'); + $this->assertFalse($this->cache->hasKey($this->key1, 'foo')); + } + + public function testNsKeyCanBeCleared() + { + $this->cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->cache->setString( + $this->key1, 'bar', 'xyz', Swift_KeyCache::MODE_WRITE + ); + $this->assertTrue($this->cache->hasKey($this->key1, 'foo')); + $this->assertTrue($this->cache->hasKey($this->key1, 'bar')); + $this->cache->clearAll($this->key1); + $this->assertFalse($this->cache->hasKey($this->key1, 'foo')); + $this->assertFalse($this->cache->hasKey($this->key1, 'bar')); + } + + public function testKeyCacheInputStream() + { + $is = $this->cache->getInputByteStream($this->key1, 'foo'); + $is->write('abc'); + $is->write('xyz'); + $this->assertEquals('abcxyz', $this->cache->getString($this->key1, 'foo')); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/MessageAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/MessageAcceptanceTest.php new file mode 100644 index 00000000..68a9b32e --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/MessageAcceptanceTest.php @@ -0,0 +1,55 @@ +createMessage(); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + + $id = $message->getId(); + $date = $message->getDate(); + $boundary = $message->getBoundary(); + + $message->addPart('foo', 'text/plain', 'iso-8859-1'); + $message->addPart('test foo', 'text/html', 'iso-8859-1'); + + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/alternative;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/plain; charset=iso-8859-1'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'foo'. + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/html; charset=iso-8859-1'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'test foo'. + "\r\n\r\n". + '--'.$boundary.'--'."\r\n", + $message->toString() + ); + } + + protected function createMessage() + { + Swift_DependencyContainer::getInstance() + ->register('properties.charset')->asValue(null); + + return new Swift_Message(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/AttachmentAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/AttachmentAcceptanceTest.php new file mode 100644 index 00000000..920faed9 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/AttachmentAcceptanceTest.php @@ -0,0 +1,126 @@ +cache = new Swift_KeyCache_ArrayKeyCache( + new Swift_KeyCache_SimpleKeyCacheInputStream() + ); + $factory = new Swift_CharacterReaderFactory_SimpleCharacterReaderFactory(); + $this->contentEncoder = new Swift_Mime_ContentEncoder_Base64ContentEncoder(); + + $headerEncoder = new Swift_Mime_HeaderEncoder_QpHeaderEncoder( + new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8') + ); + $paramEncoder = new Swift_Encoder_Rfc2231Encoder( + new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8') + ); + $this->emailValidator = new EmailValidator(); + $this->idGenerator = new Swift_Mime_IdGenerator('example.com'); + $this->headers = new Swift_Mime_SimpleHeaderSet( + new Swift_Mime_SimpleHeaderFactory($headerEncoder, $paramEncoder, $this->emailValidator) + ); + } + + public function testDispositionIsSetInHeader() + { + $attachment = $this->createAttachment(); + $attachment->setContentType('application/pdf'); + $attachment->setDisposition('inline'); + $this->assertEquals( + 'Content-Type: application/pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-Disposition: inline'."\r\n", + $attachment->toString() + ); + } + + public function testDispositionIsAttachmentByDefault() + { + $attachment = $this->createAttachment(); + $attachment->setContentType('application/pdf'); + $this->assertEquals( + 'Content-Type: application/pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-Disposition: attachment'."\r\n", + $attachment->toString() + ); + } + + public function testFilenameIsSetInHeader() + { + $attachment = $this->createAttachment(); + $attachment->setContentType('application/pdf'); + $attachment->setFilename('foo.pdf'); + $this->assertEquals( + 'Content-Type: application/pdf; name=foo.pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-Disposition: attachment; filename=foo.pdf'."\r\n", + $attachment->toString() + ); + } + + public function testSizeIsSetInHeader() + { + $attachment = $this->createAttachment(); + $attachment->setContentType('application/pdf'); + $attachment->setSize(12340); + $this->assertEquals( + 'Content-Type: application/pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-Disposition: attachment; size=12340'."\r\n", + $attachment->toString() + ); + } + + public function testMultipleParametersInHeader() + { + $attachment = $this->createAttachment(); + $attachment->setContentType('application/pdf'); + $attachment->setFilename('foo.pdf'); + $attachment->setSize(12340); + $this->assertEquals( + 'Content-Type: application/pdf; name=foo.pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-Disposition: attachment; filename=foo.pdf; size=12340'."\r\n", + $attachment->toString() + ); + } + + public function testEndToEnd() + { + $attachment = $this->createAttachment(); + $attachment->setContentType('application/pdf'); + $attachment->setFilename('foo.pdf'); + $attachment->setSize(12340); + $attachment->setBody('abcd'); + $this->assertEquals( + 'Content-Type: application/pdf; name=foo.pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-Disposition: attachment; filename=foo.pdf; size=12340'."\r\n". + "\r\n". + base64_encode('abcd'), + $attachment->toString() + ); + } + + protected function createAttachment() + { + $entity = new Swift_Mime_Attachment( + $this->headers, + $this->contentEncoder, + $this->cache, + $this->idGenerator + ); + + return $entity; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/Base64ContentEncoderAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/Base64ContentEncoderAcceptanceTest.php new file mode 100644 index 00000000..e3e9ab72 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/Base64ContentEncoderAcceptanceTest.php @@ -0,0 +1,56 @@ +samplesDir = realpath(__DIR__.'/../../../../_samples/charsets'); + $this->encoder = new Swift_Mime_ContentEncoder_Base64ContentEncoder(); + } + + public function testEncodingAndDecodingSamples() + { + $sampleFp = opendir($this->samplesDir); + while (false !== $encodingDir = readdir($sampleFp)) { + if (substr($encodingDir, 0, 1) == '.') { + continue; + } + + $sampleDir = $this->samplesDir.'/'.$encodingDir; + + if (is_dir($sampleDir)) { + $fileFp = opendir($sampleDir); + while (false !== $sampleFile = readdir($fileFp)) { + if (substr($sampleFile, 0, 1) == '.') { + continue; + } + + $text = file_get_contents($sampleDir.'/'.$sampleFile); + + $os = new Swift_ByteStream_ArrayByteStream(); + $os->write($text); + + $is = new Swift_ByteStream_ArrayByteStream(); + + $this->encoder->encodeByteStream($os, $is); + + $encoded = ''; + while (false !== $bytes = $is->read(8192)) { + $encoded .= $bytes; + } + + $this->assertEquals( + base64_decode($encoded), $text, + '%s: Encoded string should decode back to original string for sample '. + $sampleDir.'/'.$sampleFile + ); + } + closedir($fileFp); + } + } + closedir($sampleFp); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/NativeQpContentEncoderAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/NativeQpContentEncoderAcceptanceTest.php new file mode 100644 index 00000000..1efa4391 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/NativeQpContentEncoderAcceptanceTest.php @@ -0,0 +1,88 @@ +samplesDir = realpath(__DIR__.'/../../../../_samples/charsets'); + $this->encoder = new Swift_Mime_ContentEncoder_NativeQpContentEncoder(); + } + + public function testEncodingAndDecodingSamples() + { + $sampleFp = opendir($this->samplesDir); + while (false !== $encodingDir = readdir($sampleFp)) { + if (substr($encodingDir, 0, 1) == '.') { + continue; + } + + $sampleDir = $this->samplesDir.'/'.$encodingDir; + + if (is_dir($sampleDir)) { + $fileFp = opendir($sampleDir); + while (false !== $sampleFile = readdir($fileFp)) { + if (substr($sampleFile, 0, 1) == '.') { + continue; + } + + $text = file_get_contents($sampleDir.'/'.$sampleFile); + + $os = new Swift_ByteStream_ArrayByteStream(); + $os->write($text); + + $is = new Swift_ByteStream_ArrayByteStream(); + $this->encoder->encodeByteStream($os, $is); + + $encoded = ''; + while (false !== $bytes = $is->read(8192)) { + $encoded .= $bytes; + } + + $this->assertEquals( + quoted_printable_decode($encoded), + // CR and LF are converted to CRLF + preg_replace('~\r(?!\n)|(?createEncoderFromContainer(); + $this->assertSame('=C3=A4=C3=B6=C3=BC=C3=9F', $encoder->encodeString('äöüß')); + } + + /** + * @expectedException \RuntimeException + */ + public function testCharsetChangeNotImplemented() + { + $this->encoder->charsetChanged('utf-8'); + $this->encoder->charsetChanged('charset'); + $this->encoder->encodeString('foo'); + } + + public function testGetName() + { + $this->assertSame('quoted-printable', $this->encoder->getName()); + } + + private function createEncoderFromContainer() + { + return Swift_DependencyContainer::getInstance() + ->lookup('mime.nativeqpcontentencoder') + ; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/PlainContentEncoderAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/PlainContentEncoderAcceptanceTest.php new file mode 100644 index 00000000..db436917 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/PlainContentEncoderAcceptanceTest.php @@ -0,0 +1,88 @@ +samplesDir = realpath(__DIR__.'/../../../../_samples/charsets'); + $this->encoder = new Swift_Mime_ContentEncoder_PlainContentEncoder('8bit'); + } + + public function testEncodingAndDecodingSamplesString() + { + $sampleFp = opendir($this->samplesDir); + while (false !== $encodingDir = readdir($sampleFp)) { + if (substr($encodingDir, 0, 1) == '.') { + continue; + } + + $sampleDir = $this->samplesDir.'/'.$encodingDir; + + if (is_dir($sampleDir)) { + $fileFp = opendir($sampleDir); + while (false !== $sampleFile = readdir($fileFp)) { + if (substr($sampleFile, 0, 1) == '.') { + continue; + } + + $text = file_get_contents($sampleDir.'/'.$sampleFile); + $encodedText = $this->encoder->encodeString($text); + + $this->assertEquals( + $encodedText, $text, + '%s: Encoded string should be identical to original string for sample '. + $sampleDir.'/'.$sampleFile + ); + } + closedir($fileFp); + } + } + closedir($sampleFp); + } + + public function testEncodingAndDecodingSamplesByteStream() + { + $sampleFp = opendir($this->samplesDir); + while (false !== $encodingDir = readdir($sampleFp)) { + if (substr($encodingDir, 0, 1) == '.') { + continue; + } + + $sampleDir = $this->samplesDir.'/'.$encodingDir; + + if (is_dir($sampleDir)) { + $fileFp = opendir($sampleDir); + while (false !== $sampleFile = readdir($fileFp)) { + if (substr($sampleFile, 0, 1) == '.') { + continue; + } + + $text = file_get_contents($sampleDir.'/'.$sampleFile); + + $os = new Swift_ByteStream_ArrayByteStream(); + $os->write($text); + + $is = new Swift_ByteStream_ArrayByteStream(); + + $this->encoder->encodeByteStream($os, $is); + + $encoded = ''; + while (false !== $bytes = $is->read(8192)) { + $encoded .= $bytes; + } + + $this->assertEquals( + $encoded, $text, + '%s: Encoded string should be identical to original string for sample '. + $sampleDir.'/'.$sampleFile + ); + } + closedir($fileFp); + } + } + closedir($sampleFp); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/QpContentEncoderAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/QpContentEncoderAcceptanceTest.php new file mode 100644 index 00000000..7eb51155 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/ContentEncoder/QpContentEncoderAcceptanceTest.php @@ -0,0 +1,160 @@ +samplesDir = realpath(__DIR__.'/../../../../_samples/charsets'); + $this->factory = new Swift_CharacterReaderFactory_SimpleCharacterReaderFactory(); + } + + protected function tearDown() + { + Swift_Preferences::getInstance()->setQPDotEscape(false); + } + + public function testEncodingAndDecodingSamples() + { + $sampleFp = opendir($this->samplesDir); + while (false !== $encodingDir = readdir($sampleFp)) { + if (substr($encodingDir, 0, 1) == '.') { + continue; + } + + $encoding = $encodingDir; + $charStream = new Swift_CharacterStream_NgCharacterStream( + $this->factory, $encoding); + $encoder = new Swift_Mime_ContentEncoder_QpContentEncoder($charStream); + + $sampleDir = $this->samplesDir.'/'.$encodingDir; + + if (is_dir($sampleDir)) { + $fileFp = opendir($sampleDir); + while (false !== $sampleFile = readdir($fileFp)) { + if (substr($sampleFile, 0, 1) == '.') { + continue; + } + + $text = file_get_contents($sampleDir.'/'.$sampleFile); + + $os = new Swift_ByteStream_ArrayByteStream(); + $os->write($text); + + $is = new Swift_ByteStream_ArrayByteStream(); + $encoder->encodeByteStream($os, $is); + + $encoded = ''; + while (false !== $bytes = $is->read(8192)) { + $encoded .= $bytes; + } + + $this->assertEquals( + quoted_printable_decode($encoded), $text, + '%s: Encoded string should decode back to original string for sample '. + $sampleDir.'/'.$sampleFile + ); + } + closedir($fileFp); + } + } + closedir($sampleFp); + } + + public function testEncodingAndDecodingSamplesFromDiConfiguredInstance() + { + $sampleFp = opendir($this->samplesDir); + while (false !== $encodingDir = readdir($sampleFp)) { + if (substr($encodingDir, 0, 1) == '.') { + continue; + } + + $encoding = $encodingDir; + $encoder = $this->createEncoderFromContainer(); + + $sampleDir = $this->samplesDir.'/'.$encodingDir; + + if (is_dir($sampleDir)) { + $fileFp = opendir($sampleDir); + while (false !== $sampleFile = readdir($fileFp)) { + if (substr($sampleFile, 0, 1) == '.') { + continue; + } + + $text = file_get_contents($sampleDir.'/'.$sampleFile); + + $os = new Swift_ByteStream_ArrayByteStream(); + $os->write($text); + + $is = new Swift_ByteStream_ArrayByteStream(); + $encoder->encodeByteStream($os, $is); + + $encoded = ''; + while (false !== $bytes = $is->read(8192)) { + $encoded .= $bytes; + } + + $this->assertEquals( + str_replace("\r\n", "\n", quoted_printable_decode($encoded)), str_replace("\r\n", "\n", $text), + '%s: Encoded string should decode back to original string for sample '. + $sampleDir.'/'.$sampleFile + ); + } + closedir($fileFp); + } + } + closedir($sampleFp); + } + + public function testEncodingLFTextWithDiConfiguredInstance() + { + $encoder = $this->createEncoderFromContainer(); + $this->assertEquals("a\r\nb\r\nc", $encoder->encodeString("a\nb\nc")); + } + + public function testEncodingCRTextWithDiConfiguredInstance() + { + $encoder = $this->createEncoderFromContainer(); + $this->assertEquals("a\r\nb\r\nc", $encoder->encodeString("a\rb\rc")); + } + + public function testEncodingLFCRTextWithDiConfiguredInstance() + { + $encoder = $this->createEncoderFromContainer(); + $this->assertEquals("a\r\n\r\nb\r\n\r\nc", $encoder->encodeString("a\n\rb\n\rc")); + } + + public function testEncodingCRLFTextWithDiConfiguredInstance() + { + $encoder = $this->createEncoderFromContainer(); + $this->assertEquals("a\r\nb\r\nc", $encoder->encodeString("a\r\nb\r\nc")); + } + + public function testEncodingDotStuffingWithDiConfiguredInstance() + { + // Enable DotEscaping + Swift_Preferences::getInstance()->setQPDotEscape(true); + $encoder = $this->createEncoderFromContainer(); + $this->assertEquals("a=2E\r\n=2E\r\n=2Eb\r\nc", $encoder->encodeString("a.\r\n.\r\n.b\r\nc")); + // Return to default + Swift_Preferences::getInstance()->setQPDotEscape(false); + $encoder = $this->createEncoderFromContainer(); + $this->assertEquals("a.\r\n.\r\n.b\r\nc", $encoder->encodeString("a.\r\n.\r\n.b\r\nc")); + } + + public function testDotStuffingEncodingAndDecodingSamplesFromDiConfiguredInstance() + { + // Enable DotEscaping + Swift_Preferences::getInstance()->setQPDotEscape(true); + $this->testEncodingAndDecodingSamplesFromDiConfiguredInstance(); + } + + private function createEncoderFromContainer() + { + return Swift_DependencyContainer::getInstance() + ->lookup('mime.qpcontentencoder') + ; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/EmbeddedFileAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/EmbeddedFileAcceptanceTest.php new file mode 100644 index 00000000..5603a67d --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/EmbeddedFileAcceptanceTest.php @@ -0,0 +1,139 @@ +cache = new Swift_KeyCache_ArrayKeyCache( + new Swift_KeyCache_SimpleKeyCacheInputStream() + ); + $factory = new Swift_CharacterReaderFactory_SimpleCharacterReaderFactory(); + $this->contentEncoder = new Swift_Mime_ContentEncoder_Base64ContentEncoder(); + + $headerEncoder = new Swift_Mime_HeaderEncoder_QpHeaderEncoder( + new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8') + ); + $paramEncoder = new Swift_Encoder_Rfc2231Encoder( + new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8') + ); + $this->emailValidator = new EmailValidator(); + $this->idGenerator = new Swift_Mime_IdGenerator('example.com'); + $this->headers = new Swift_Mime_SimpleHeaderSet( + new Swift_Mime_SimpleHeaderFactory($headerEncoder, $paramEncoder, $this->emailValidator) + ); + } + + public function testContentIdIsSetInHeader() + { + $file = $this->createEmbeddedFile(); + $file->setContentType('application/pdf'); + $file->setId('foo@bar'); + $this->assertEquals( + 'Content-Type: application/pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-ID: '."\r\n". + 'Content-Disposition: inline'."\r\n", + $file->toString() + ); + } + + public function testDispositionIsSetInHeader() + { + $file = $this->createEmbeddedFile(); + $id = $file->getId(); + $file->setContentType('application/pdf'); + $file->setDisposition('attachment'); + $this->assertEquals( + 'Content-Type: application/pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-ID: <'.$id.'>'."\r\n". + 'Content-Disposition: attachment'."\r\n", + $file->toString() + ); + } + + public function testFilenameIsSetInHeader() + { + $file = $this->createEmbeddedFile(); + $id = $file->getId(); + $file->setContentType('application/pdf'); + $file->setFilename('foo.pdf'); + $this->assertEquals( + 'Content-Type: application/pdf; name=foo.pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-ID: <'.$id.'>'."\r\n". + 'Content-Disposition: inline; filename=foo.pdf'."\r\n", + $file->toString() + ); + } + + public function testSizeIsSetInHeader() + { + $file = $this->createEmbeddedFile(); + $id = $file->getId(); + $file->setContentType('application/pdf'); + $file->setSize(12340); + $this->assertEquals( + 'Content-Type: application/pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-ID: <'.$id.'>'."\r\n". + 'Content-Disposition: inline; size=12340'."\r\n", + $file->toString() + ); + } + + public function testMultipleParametersInHeader() + { + $file = $this->createEmbeddedFile(); + $id = $file->getId(); + $file->setContentType('application/pdf'); + $file->setFilename('foo.pdf'); + $file->setSize(12340); + + $this->assertEquals( + 'Content-Type: application/pdf; name=foo.pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-ID: <'.$id.'>'."\r\n". + 'Content-Disposition: inline; filename=foo.pdf; size=12340'."\r\n", + $file->toString() + ); + } + + public function testEndToEnd() + { + $file = $this->createEmbeddedFile(); + $id = $file->getId(); + $file->setContentType('application/pdf'); + $file->setFilename('foo.pdf'); + $file->setSize(12340); + $file->setBody('abcd'); + $this->assertEquals( + 'Content-Type: application/pdf; name=foo.pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-ID: <'.$id.'>'."\r\n". + 'Content-Disposition: inline; filename=foo.pdf; size=12340'."\r\n". + "\r\n". + base64_encode('abcd'), + $file->toString() + ); + } + + protected function createEmbeddedFile() + { + $entity = new Swift_Mime_EmbeddedFile( + $this->headers, + $this->contentEncoder, + $this->cache, + $this->idGenerator + ); + + return $entity; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/HeaderEncoder/Base64HeaderEncoderAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/HeaderEncoder/Base64HeaderEncoderAcceptanceTest.php new file mode 100644 index 00000000..13795135 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/HeaderEncoder/Base64HeaderEncoderAcceptanceTest.php @@ -0,0 +1,32 @@ +encoder = new Swift_Mime_HeaderEncoder_Base64HeaderEncoder(); + } + + public function testEncodingJIS() + { + if (function_exists('mb_convert_encoding')) { + // base64_encode and split cannot handle long JIS text to fold + $subject = '長い長い長い長い長い長い長い長い長い長い長い長い長い長い長い長い長い長い長い長い件名'; + + $encodedWrapperLength = strlen('=?iso-2022-jp?'.$this->encoder->getName().'??='); + + $old = mb_internal_encoding(); + mb_internal_encoding('utf-8'); + $newstring = mb_encode_mimeheader($subject, 'iso-2022-jp', 'B', "\r\n"); + mb_internal_encoding($old); + + $encoded = $this->encoder->encodeString($subject, 0, 75 - $encodedWrapperLength, 'iso-2022-jp'); + $this->assertEquals( + $encoded, $newstring, + 'Encoded string should decode back to original string for sample ' + ); + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/MimePartAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/MimePartAcceptanceTest.php new file mode 100644 index 00000000..0a1f02a3 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/MimePartAcceptanceTest.php @@ -0,0 +1,130 @@ +cache = new Swift_KeyCache_ArrayKeyCache( + new Swift_KeyCache_SimpleKeyCacheInputStream() + ); + $factory = new Swift_CharacterReaderFactory_SimpleCharacterReaderFactory(); + $this->contentEncoder = new Swift_Mime_ContentEncoder_QpContentEncoder( + new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8'), + new Swift_StreamFilters_ByteArrayReplacementFilter( + array(array(0x0D, 0x0A), array(0x0D), array(0x0A)), + array(array(0x0A), array(0x0A), array(0x0D, 0x0A)) + ) + ); + + $headerEncoder = new Swift_Mime_HeaderEncoder_QpHeaderEncoder( + new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8') + ); + $paramEncoder = new Swift_Encoder_Rfc2231Encoder( + new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8') + ); + $this->emailValidator = new EmailValidator(); + $this->idGenerator = new Swift_Mime_IdGenerator('example.com'); + $this->headers = new Swift_Mime_SimpleHeaderSet( + new Swift_Mime_SimpleHeaderFactory($headerEncoder, $paramEncoder, $this->emailValidator) + ); + } + + public function testCharsetIsSetInHeader() + { + $part = $this->createMimePart(); + $part->setContentType('text/plain'); + $part->setCharset('utf-8'); + $part->setBody('foobar'); + $this->assertEquals( + 'Content-Type: text/plain; charset=utf-8'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'foobar', + $part->toString() + ); + } + + public function testFormatIsSetInHeaders() + { + $part = $this->createMimePart(); + $part->setContentType('text/plain'); + $part->setFormat('flowed'); + $part->setBody('> foobar'); + $this->assertEquals( + 'Content-Type: text/plain; format=flowed'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + '> foobar', + $part->toString() + ); + } + + public function testDelSpIsSetInHeaders() + { + $part = $this->createMimePart(); + $part->setContentType('text/plain'); + $part->setDelSp(true); + $part->setBody('foobar'); + $this->assertEquals( + 'Content-Type: text/plain; delsp=yes'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'foobar', + $part->toString() + ); + } + + public function testAll3ParamsInHeaders() + { + $part = $this->createMimePart(); + $part->setContentType('text/plain'); + $part->setCharset('utf-8'); + $part->setFormat('fixed'); + $part->setDelSp(true); + $part->setBody('foobar'); + $this->assertEquals( + 'Content-Type: text/plain; charset=utf-8; format=fixed; delsp=yes'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'foobar', + $part->toString() + ); + } + + public function testBodyIsCanonicalized() + { + $part = $this->createMimePart(); + $part->setContentType('text/plain'); + $part->setCharset('utf-8'); + $part->setBody("foobar\r\rtest\ning\r"); + $this->assertEquals( + 'Content-Type: text/plain; charset=utf-8'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + "foobar\r\n". + "\r\n". + "test\r\n". + "ing\r\n", + $part->toString() + ); + } + + protected function createMimePart() + { + $entity = new Swift_Mime_MimePart( + $this->headers, + $this->contentEncoder, + $this->cache, + $this->idGenerator + ); + + return $entity; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/SimpleMessageAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/SimpleMessageAcceptanceTest.php new file mode 100644 index 00000000..246a58bb --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Mime/SimpleMessageAcceptanceTest.php @@ -0,0 +1,1250 @@ +setCharset(null); //TODO: Test with the charset defined + } + + public function testBasicHeaders() + { + /* -- RFC 2822, 3.6. + */ + + $message = $this->createMessage(); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'From: '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString(), + '%s: Only required headers, and non-empty headers should be displayed' + ); + } + + public function testSubjectIsDisplayedIfSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testDateCanBeSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $id = $message->getId(); + $date = new DateTimeImmutable(); + $message->setDate($date); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testMessageIdCanBeSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setId('foo@bar'); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: '."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testContentTypeCanBeChanged() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setContentType('text/html'); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/html'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testCharsetCanBeSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setContentType('text/html'); + $message->setCharset('iso-8859-1'); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/html; charset=iso-8859-1'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testFormatCanBeSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setFormat('flowed'); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain; format=flowed'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testEncoderCanBeSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setContentType('text/html'); + $message->setEncoder( + new Swift_Mime_ContentEncoder_PlainContentEncoder('7bit') + ); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/html'."\r\n". + 'Content-Transfer-Encoding: 7bit'."\r\n", + $message->toString() + ); + } + + public function testFromAddressCanBeSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setFrom('chris.corbyn@swiftmailer.org'); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: chris.corbyn@swiftmailer.org'."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testFromAddressCanBeSetWithName() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setFrom(array('chris.corbyn@swiftmailer.org' => 'Chris Corbyn')); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testMultipleFromAddressesCanBeSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', + 'mark@swiftmailer.org', + )); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn , mark@swiftmailer.org'."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testReturnPathAddressCanBeSet() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testEmptyReturnPathHeaderCanBeUsed() + { + $message = $this->createMessage(); + $message->setReturnPath(''); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Return-Path: <>'."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testSenderCanBeSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setSender('chris.corbyn@swiftmailer.org'); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Sender: chris.corbyn@swiftmailer.org'."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testSenderCanBeSetWithName() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setSender(array('chris.corbyn@swiftmailer.org' => 'Chris')); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Sender: Chris '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testReplyToCanBeSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setFrom(array('chris.corbyn@swiftmailer.org' => 'Chris')); + $message->setReplyTo(array('chris@w3style.co.uk' => 'Myself')); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris '."\r\n". + 'Reply-To: Myself '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testMultipleReplyAddressCanBeUsed() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setFrom(array('chris.corbyn@swiftmailer.org' => 'Chris')); + $message->setReplyTo(array( + 'chris@w3style.co.uk' => 'Myself', + 'my.other@address.com' => 'Me', + )); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris '."\r\n". + 'Reply-To: Myself , Me '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testToAddressCanBeSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setFrom(array('chris.corbyn@swiftmailer.org' => 'Chris')); + $message->setReplyTo(array( + 'chris@w3style.co.uk' => 'Myself', + 'my.other@address.com' => 'Me', + )); + $message->setTo('mark@swiftmailer.org'); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris '."\r\n". + 'Reply-To: Myself , Me '."\r\n". + 'To: mark@swiftmailer.org'."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testMultipleToAddressesCanBeSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setFrom(array('chris.corbyn@swiftmailer.org' => 'Chris')); + $message->setReplyTo(array( + 'chris@w3style.co.uk' => 'Myself', + 'my.other@address.com' => 'Me', + )); + $message->setTo(array( + 'mark@swiftmailer.org', 'chris@swiftmailer.org' => 'Chris Corbyn', + )); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris '."\r\n". + 'Reply-To: Myself , Me '."\r\n". + 'To: mark@swiftmailer.org, Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testCcAddressCanBeSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setFrom(array('chris.corbyn@swiftmailer.org' => 'Chris')); + $message->setReplyTo(array( + 'chris@w3style.co.uk' => 'Myself', + 'my.other@address.com' => 'Me', + )); + $message->setTo(array( + 'mark@swiftmailer.org', 'chris@swiftmailer.org' => 'Chris Corbyn', + )); + $message->setCc('john@some-site.com'); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris '."\r\n". + 'Reply-To: Myself , Me '."\r\n". + 'To: mark@swiftmailer.org, Chris Corbyn '."\r\n". + 'Cc: john@some-site.com'."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testMultipleCcAddressesCanBeSet() + { + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setFrom(array('chris.corbyn@swiftmailer.org' => 'Chris')); + $message->setReplyTo(array( + 'chris@w3style.co.uk' => 'Myself', + 'my.other@address.com' => 'Me', + )); + $message->setTo(array( + 'mark@swiftmailer.org', 'chris@swiftmailer.org' => 'Chris Corbyn', + )); + $message->setCc(array( + 'john@some-site.com' => 'John West', + 'fred@another-site.co.uk' => 'Big Fred', + )); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris '."\r\n". + 'Reply-To: Myself , Me '."\r\n". + 'To: mark@swiftmailer.org, Chris Corbyn '."\r\n". + 'Cc: John West , Big Fred '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testBccAddressCanBeSet() + { + //Obviously Transports need to setBcc(array()) and send to each Bcc recipient + // separately in accordance with RFC 2822/2821 + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setFrom(array('chris.corbyn@swiftmailer.org' => 'Chris')); + $message->setReplyTo(array( + 'chris@w3style.co.uk' => 'Myself', + 'my.other@address.com' => 'Me', + )); + $message->setTo(array( + 'mark@swiftmailer.org', 'chris@swiftmailer.org' => 'Chris Corbyn', + )); + $message->setCc(array( + 'john@some-site.com' => 'John West', + 'fred@another-site.co.uk' => 'Big Fred', + )); + $message->setBcc('x@alphabet.tld'); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris '."\r\n". + 'Reply-To: Myself , Me '."\r\n". + 'To: mark@swiftmailer.org, Chris Corbyn '."\r\n". + 'Cc: John West , Big Fred '."\r\n". + 'Bcc: x@alphabet.tld'."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testMultipleBccAddressesCanBeSet() + { + //Obviously Transports need to setBcc(array()) and send to each Bcc recipient + // separately in accordance with RFC 2822/2821 + $message = $this->createMessage(); + $message->setSubject('just a test subject'); + $message->setFrom(array('chris.corbyn@swiftmailer.org' => 'Chris')); + $message->setReplyTo(array( + 'chris@w3style.co.uk' => 'Myself', + 'my.other@address.com' => 'Me', + )); + $message->setTo(array( + 'mark@swiftmailer.org', 'chris@swiftmailer.org' => 'Chris Corbyn', + )); + $message->setCc(array( + 'john@some-site.com' => 'John West', + 'fred@another-site.co.uk' => 'Big Fred', + )); + $message->setBcc(array('x@alphabet.tld', 'a@alphabet.tld' => 'A')); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris '."\r\n". + 'Reply-To: Myself , Me '."\r\n". + 'To: mark@swiftmailer.org, Chris Corbyn '."\r\n". + 'Cc: John West , Big Fred '."\r\n". + 'Bcc: x@alphabet.tld, A '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString() + ); + } + + public function testStringBodyIsAppended() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + $message->setBody( + 'just a test body'."\r\n". + 'with a new line' + ); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'just a test body'."\r\n". + 'with a new line', + $message->toString() + ); + } + + public function testStringBodyIsEncoded() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + $message->setBody( + 'Just s'.pack('C*', 0xC2, 0x01, 0x01).'me multi-'."\r\n". + 'line message!' + ); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'Just s=C2=01=01me multi-'."\r\n". + 'line message!', + $message->toString() + ); + } + + public function testChildrenCanBeAttached() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + + $id = $message->getId(); + $date = $message->getDate(); + $boundary = $message->getBoundary(); + + $part1 = $this->createMimePart(); + $part1->setContentType('text/plain'); + $part1->setCharset('iso-8859-1'); + $part1->setBody('foo'); + + $message->attach($part1); + + $part2 = $this->createMimePart(); + $part2->setContentType('text/html'); + $part2->setCharset('iso-8859-1'); + $part2->setBody('test foo'); + + $message->attach($part2); + + $this->assertEquals( + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/alternative;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/plain; charset=iso-8859-1'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'foo'. + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/html; charset=iso-8859-1'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'test foo'. + "\r\n\r\n". + '--'.$boundary.'--'."\r\n", + $message->toString() + ); + } + + public function testAttachmentsBeingAttached() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + + $id = $message->getId(); + $date = preg_quote($message->getDate()->format('r'), '~'); + $boundary = $message->getBoundary(); + + $part = $this->createMimePart(); + $part->setContentType('text/plain'); + $part->setCharset('iso-8859-1'); + $part->setBody('foo'); + + $message->attach($part); + + $attachment = $this->createAttachment(); + $attachment->setContentType('application/pdf'); + $attachment->setFilename('foo.pdf'); + $attachment->setBody(''); + + $message->attach($attachment); + + $this->assertRegExp( + '~^'. + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/mixed;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: multipart/alternative;'."\r\n". + ' boundary="(.*?)"'."\r\n". + "\r\n\r\n". + '--\\1'."\r\n". + 'Content-Type: text/plain; charset=iso-8859-1'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'foo'. + "\r\n\r\n". + '--\\1--'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: application/pdf; name=foo.pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-Disposition: attachment; filename=foo.pdf'."\r\n". + "\r\n". + preg_quote(base64_encode(''), '~'). + "\r\n\r\n". + '--'.$boundary.'--'."\r\n". + '$~D', + $message->toString() + ); + } + + public function testAttachmentsAndEmbeddedFilesBeingAttached() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + + $id = $message->getId(); + $date = preg_quote($message->getDate()->format('r'), '~'); + $boundary = $message->getBoundary(); + + $part = $this->createMimePart(); + $part->setContentType('text/plain'); + $part->setCharset('iso-8859-1'); + $part->setBody('foo'); + + $message->attach($part); + + $attachment = $this->createAttachment(); + $attachment->setContentType('application/pdf'); + $attachment->setFilename('foo.pdf'); + $attachment->setBody(''); + + $message->attach($attachment); + + $file = $this->createEmbeddedFile(); + $file->setContentType('image/jpeg'); + $file->setFilename('myimage.jpg'); + $file->setBody(''); + + $message->attach($file); + + $cid = $file->getId(); + + $this->assertRegExp( + '~^'. + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/mixed;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: multipart/alternative;'."\r\n". + ' boundary="(.*?)"'."\r\n". + "\r\n\r\n". + '--\\1'."\r\n". + 'Content-Type: text/plain; charset=iso-8859-1'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'foo'. + + "\r\n\r\n". + '--\\1'."\r\n". + 'Content-Type: multipart/related;'."\r\n". + ' boundary="(.*?)"'."\r\n". + "\r\n\r\n". + '--\\2'."\r\n". + 'Content-Type: image/jpeg; name=myimage.jpg'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-ID: <'.$cid.'>'."\r\n". + 'Content-Disposition: inline; filename=myimage.jpg'."\r\n". + "\r\n". + preg_quote(base64_encode(''), '~'). + "\r\n\r\n". + '--\\2--'."\r\n". + "\r\n\r\n". + '--\\1--'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: application/pdf; name=foo.pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-Disposition: attachment; filename=foo.pdf'."\r\n". + "\r\n". + preg_quote(base64_encode(''), '~'). + "\r\n\r\n". + '--'.$boundary.'--'."\r\n". + '$~D', + $message->toString() + ); + } + + public function testComplexEmbeddingOfContent() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + + $id = $message->getId(); + $date = preg_quote($message->getDate()->format('r'), '~'); + $boundary = $message->getBoundary(); + + $attachment = $this->createAttachment(); + $attachment->setContentType('application/pdf'); + $attachment->setFilename('foo.pdf'); + $attachment->setBody(''); + + $message->attach($attachment); + + $file = $this->createEmbeddedFile(); + $file->setContentType('image/jpeg'); + $file->setFilename('myimage.jpg'); + $file->setBody(''); + + $part = $this->createMimePart(); + $part->setContentType('text/html'); + $part->setCharset('iso-8859-1'); + $part->setBody('foo '); + + $message->attach($part); + + $cid = $file->getId(); + + $this->assertRegExp( + '~^'. + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/mixed;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: multipart/related;'."\r\n". + ' boundary="(.*?)"'."\r\n". + "\r\n\r\n". + '--\\1'."\r\n". + 'Content-Type: text/html; charset=iso-8859-1'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'foo './/=3D is just = in QP + "\r\n\r\n". + '--\\1'."\r\n". + 'Content-Type: image/jpeg; name=myimage.jpg'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-ID: <'.$cid.'>'."\r\n". + 'Content-Disposition: inline; filename=myimage.jpg'."\r\n". + "\r\n". + preg_quote(base64_encode(''), '~'). + "\r\n\r\n". + '--\\1--'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: application/pdf; name=foo.pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-Disposition: attachment; filename=foo.pdf'."\r\n". + "\r\n". + preg_quote(base64_encode(''), '~'). + "\r\n\r\n". + '--'.$boundary.'--'."\r\n". + '$~D', + $message->toString() + ); + } + + public function testAttachingAndDetachingContent() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + + $id = $message->getId(); + $date = preg_quote($message->getDate()->format('r'), '~'); + $boundary = $message->getBoundary(); + + $part = $this->createMimePart(); + $part->setContentType('text/plain'); + $part->setCharset('iso-8859-1'); + $part->setBody('foo'); + + $message->attach($part); + + $attachment = $this->createAttachment(); + $attachment->setContentType('application/pdf'); + $attachment->setFilename('foo.pdf'); + $attachment->setBody(''); + + $message->attach($attachment); + + $file = $this->createEmbeddedFile(); + $file->setContentType('image/jpeg'); + $file->setFilename('myimage.jpg'); + $file->setBody(''); + + $message->attach($file); + + $cid = $file->getId(); + + $message->detach($attachment); + + $this->assertRegExp( + '~^'. + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/alternative;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/plain; charset=iso-8859-1'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'foo'. + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: multipart/related;'."\r\n". + ' boundary="(.*?)"'."\r\n". + "\r\n\r\n". + '--\\1'."\r\n". + 'Content-Type: image/jpeg; name=myimage.jpg'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-ID: <'.$cid.'>'."\r\n". + 'Content-Disposition: inline; filename=myimage.jpg'."\r\n". + "\r\n". + preg_quote(base64_encode(''), '~'). + "\r\n\r\n". + '--\\1--'."\r\n". + "\r\n\r\n". + '--'.$boundary.'--'."\r\n". + '$~D', + $message->toString(), + '%s: Attachment should have been detached' + ); + } + + public function testBoundaryDoesNotAppearAfterAllPartsAreDetached() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + + $id = $message->getId(); + $date = $message->getDate(); + $boundary = $message->getBoundary(); + + $part1 = $this->createMimePart(); + $part1->setContentType('text/plain'); + $part1->setCharset('iso-8859-1'); + $part1->setBody('foo'); + + $message->attach($part1); + + $part2 = $this->createMimePart(); + $part2->setContentType('text/html'); + $part2->setCharset('iso-8859-1'); + $part2->setBody('test foo'); + + $message->attach($part2); + + $message->detach($part1); + $message->detach($part2); + + $this->assertEquals( + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n", + $message->toString(), + '%s: Message should be restored to orignal state after parts are detached' + ); + } + + public function testCharsetFormatOrDelSpAreNotShownWhenBoundaryIsSet() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + $message->setCharset('utf-8'); + $message->setFormat('flowed'); + $message->setDelSp(true); + + $id = $message->getId(); + $date = $message->getDate(); + $boundary = $message->getBoundary(); + + $part1 = $this->createMimePart(); + $part1->setContentType('text/plain'); + $part1->setCharset('iso-8859-1'); + $part1->setBody('foo'); + + $message->attach($part1); + + $part2 = $this->createMimePart(); + $part2->setContentType('text/html'); + $part2->setCharset('iso-8859-1'); + $part2->setBody('test foo'); + + $message->attach($part2); + + $this->assertEquals( + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/alternative;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/plain; charset=iso-8859-1'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'foo'. + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/html; charset=iso-8859-1'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'test foo'. + "\r\n\r\n". + '--'.$boundary.'--'."\r\n", + $message->toString() + ); + } + + public function testBodyCanBeSetWithAttachments() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + $message->setContentType('text/html'); + $message->setCharset('iso-8859-1'); + $message->setBody('foo'); + + $id = $message->getId(); + $date = $message->getDate()->format('r'); + $boundary = $message->getBoundary(); + + $attachment = $this->createAttachment(); + $attachment->setContentType('application/pdf'); + $attachment->setFilename('foo.pdf'); + $attachment->setBody(''); + + $message->attach($attachment); + + $this->assertEquals( + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/mixed;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/html; charset=iso-8859-1'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'foo'. + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: application/pdf; name=foo.pdf'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-Disposition: attachment; filename=foo.pdf'."\r\n". + "\r\n". + base64_encode(''). + "\r\n\r\n". + '--'.$boundary.'--'."\r\n", + $message->toString() + ); + } + + public function testHtmlPartAlwaysAppearsLast() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + + $id = $message->getId(); + $date = $message->getDate()->format('r'); + $boundary = $message->getBoundary(); + + $part1 = $this->createMimePart(); + $part1->setContentType('text/html'); + $part1->setBody('foo'); + + $part2 = $this->createMimePart(); + $part2->setContentType('text/plain'); + $part2->setBody('bar'); + + $message->attach($part1); + $message->attach($part2); + + $this->assertEquals( + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/alternative;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'bar'. + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/html'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'foo'. + "\r\n\r\n". + '--'.$boundary.'--'."\r\n", + $message->toString() + ); + } + + public function testBodyBecomesPartIfOtherPartsAttached() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + $message->setContentType('text/html'); + $message->setBody('foo'); + + $id = $message->getId(); + $date = $message->getDate()->format('r'); + $boundary = $message->getBoundary(); + + $part2 = $this->createMimePart(); + $part2->setContentType('text/plain'); + $part2->setBody('bar'); + + $message->attach($part2); + + $this->assertEquals( + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/alternative;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'bar'. + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/html'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'foo'. + "\r\n\r\n". + '--'.$boundary.'--'."\r\n", + $message->toString() + ); + } + + public function testBodyIsCanonicalized() + { + $message = $this->createMessage(); + $message->setReturnPath('chris@w3style.co.uk'); + $message->setSubject('just a test subject'); + $message->setFrom(array( + 'chris.corbyn@swiftmailer.org' => 'Chris Corbyn', )); + $message->setBody( + 'just a test body'."\n". + 'with a new line' + ); + $id = $message->getId(); + $date = $message->getDate(); + $this->assertEquals( + 'Return-Path: '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date->format('r')."\r\n". + 'Subject: just a test subject'."\r\n". + 'From: Chris Corbyn '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: text/plain'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'just a test body'."\r\n". + 'with a new line', + $message->toString() + ); + } + + protected function createMessage() + { + return new Swift_Message(); + } + + protected function createMimePart() + { + return new Swift_MimePart(); + } + + protected function createAttachment() + { + return new Swift_Attachment(); + } + + protected function createEmbeddedFile() + { + return new Swift_EmbeddedFile(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/MimePartAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/MimePartAcceptanceTest.php new file mode 100644 index 00000000..581afc7d --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/MimePartAcceptanceTest.php @@ -0,0 +1,15 @@ +register('properties.charset')->asValue(null); + + return new Swift_MimePart(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/AbstractStreamBufferAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/AbstractStreamBufferAcceptanceTest.php new file mode 100644 index 00000000..9bc09f88 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/AbstractStreamBufferAcceptanceTest.php @@ -0,0 +1,131 @@ +markTestSkipped( + 'Will fail on travis-ci if not skipped due to travis blocking '. + 'socket mailing tcp connections.' + ); + } + + $this->buffer = new Swift_Transport_StreamBuffer( + $this->getMockBuilder('Swift_ReplacementFilterFactory')->getMock() + ); + } + + public function testReadLine() + { + $this->initializeBuffer(); + + $line = $this->buffer->readLine(0); + $this->assertRegExp('/^[0-9]{3}.*?\r\n$/D', $line); + $seq = $this->buffer->write("QUIT\r\n"); + $this->assertTrue((bool) $seq); + $line = $this->buffer->readLine($seq); + $this->assertRegExp('/^[0-9]{3}.*?\r\n$/D', $line); + $this->buffer->terminate(); + } + + public function testWrite() + { + $this->initializeBuffer(); + + $line = $this->buffer->readLine(0); + $this->assertRegExp('/^[0-9]{3}.*?\r\n$/D', $line); + + $seq = $this->buffer->write("HELO foo\r\n"); + $this->assertTrue((bool) $seq); + $line = $this->buffer->readLine($seq); + $this->assertRegExp('/^[0-9]{3}.*?\r\n$/D', $line); + + $seq = $this->buffer->write("QUIT\r\n"); + $this->assertTrue((bool) $seq); + $line = $this->buffer->readLine($seq); + $this->assertRegExp('/^[0-9]{3}.*?\r\n$/D', $line); + $this->buffer->terminate(); + } + + public function testBindingOtherStreamsMirrorsWriteOperations() + { + $this->initializeBuffer(); + + $is1 = $this->createMockInputStream(); + $is2 = $this->createMockInputStream(); + + $is1->expects($this->at(0)) + ->method('write') + ->with('x'); + $is1->expects($this->at(1)) + ->method('write') + ->with('y'); + $is2->expects($this->at(0)) + ->method('write') + ->with('x'); + $is2->expects($this->at(1)) + ->method('write') + ->with('y'); + + $this->buffer->bind($is1); + $this->buffer->bind($is2); + + $this->buffer->write('x'); + $this->buffer->write('y'); + } + + public function testBindingOtherStreamsMirrorsFlushOperations() + { + $this->initializeBuffer(); + + $is1 = $this->createMockInputStream(); + $is2 = $this->createMockInputStream(); + + $is1->expects($this->once()) + ->method('flushBuffers'); + $is2->expects($this->once()) + ->method('flushBuffers'); + + $this->buffer->bind($is1); + $this->buffer->bind($is2); + + $this->buffer->flushBuffers(); + } + + public function testUnbindingStreamPreventsFurtherWrites() + { + $this->initializeBuffer(); + + $is1 = $this->createMockInputStream(); + $is2 = $this->createMockInputStream(); + + $is1->expects($this->at(0)) + ->method('write') + ->with('x'); + $is1->expects($this->at(1)) + ->method('write') + ->with('y'); + $is2->expects($this->once()) + ->method('write') + ->with('x'); + + $this->buffer->bind($is1); + $this->buffer->bind($is2); + + $this->buffer->write('x'); + + $this->buffer->unbind($is2); + + $this->buffer->write('y'); + } + + private function createMockInputStream() + { + return $this->getMockBuilder('Swift_InputByteStream')->getMock(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/BasicSocketAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/BasicSocketAcceptanceTest.php new file mode 100644 index 00000000..85b2f4ec --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/BasicSocketAcceptanceTest.php @@ -0,0 +1,33 @@ +markTestSkipped( + 'Cannot run test without an SMTP host to connect to (define '. + 'SWIFT_SMTP_HOST in tests/acceptance.conf.php if you wish to run this test)' + ); + } + parent::setUp(); + } + + protected function initializeBuffer() + { + $parts = explode(':', SWIFT_SMTP_HOST); + $host = $parts[0]; + $port = isset($parts[1]) ? $parts[1] : 25; + + $this->buffer->initialize(array( + 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET, + 'host' => $host, + 'port' => $port, + 'protocol' => 'tcp', + 'blocking' => 1, + 'timeout' => 15, + )); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/ProcessAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/ProcessAcceptanceTest.php new file mode 100644 index 00000000..4435d6f3 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/ProcessAcceptanceTest.php @@ -0,0 +1,26 @@ +markTestSkipped( + 'Cannot run test without a path to sendmail (define '. + 'SWIFT_SENDMAIL_PATH in tests/acceptance.conf.php if you wish to run this test)' + ); + } + + parent::setUp(); + } + + protected function initializeBuffer() + { + $this->buffer->initialize(array( + 'type' => Swift_Transport_IoBuffer::TYPE_PROCESS, + 'command' => SWIFT_SENDMAIL_PATH.' -bs', + )); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/SocketTimeoutTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/SocketTimeoutTest.php new file mode 100644 index 00000000..1291b128 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/SocketTimeoutTest.php @@ -0,0 +1,65 @@ +markTestSkipped( + 'Cannot run test without an SMTP host to connect to (define '. + 'SWIFT_SMTP_HOST in tests/acceptance.conf.php if you wish to run this test)' + ); + } + + $serverStarted = false; + for ($i = 0; $i < 5; ++$i) { + $this->randomHighPort = random_int(50000, 65000); + $this->server = stream_socket_server('tcp://127.0.0.1:'.$this->randomHighPort); + if ($this->server) { + $serverStarted = true; + } + } + + $this->buffer = new Swift_Transport_StreamBuffer( + $this->getMockBuilder('Swift_ReplacementFilterFactory')->getMock() + ); + } + + protected function initializeBuffer() + { + $host = '127.0.0.1'; + $port = $this->randomHighPort; + + $this->buffer->initialize(array( + 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET, + 'host' => $host, + 'port' => $port, + 'protocol' => 'tcp', + 'blocking' => 1, + 'timeout' => 1, + )); + } + + public function testTimeoutException() + { + $this->initializeBuffer(); + $e = null; + try { + $line = $this->buffer->readLine(0); + } catch (Exception $e) { + } + $this->assertInstanceOf('Swift_IoException', $e, 'IO Exception Not Thrown On Connection Timeout'); + $this->assertRegExp('/Connection to .* Timed Out/', $e->getMessage()); + } + + protected function tearDown() + { + if ($this->server) { + stream_socket_shutdown($this->server, STREAM_SHUT_RDWR); + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/SslSocketAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/SslSocketAcceptanceTest.php new file mode 100644 index 00000000..abd7582d --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/SslSocketAcceptanceTest.php @@ -0,0 +1,40 @@ +markTestSkipped( + 'SSL is not configured for your system. It is not possible to run this test' + ); + } + if (!defined('SWIFT_SSL_HOST')) { + $this->markTestSkipped( + 'Cannot run test without an SSL enabled SMTP host to connect to (define '. + 'SWIFT_SSL_HOST in tests/acceptance.conf.php if you wish to run this test)' + ); + } + + parent::setUp(); + } + + protected function initializeBuffer() + { + $parts = explode(':', SWIFT_SSL_HOST); + $host = $parts[0]; + $port = isset($parts[1]) ? $parts[1] : 25; + + $this->buffer->initialize(array( + 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET, + 'host' => $host, + 'port' => $port, + 'protocol' => 'ssl', + 'blocking' => 1, + 'timeout' => 15, + )); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/TlsSocketAcceptanceTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/TlsSocketAcceptanceTest.php new file mode 100644 index 00000000..3148dbdc --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/acceptance/Swift/Transport/StreamBuffer/TlsSocketAcceptanceTest.php @@ -0,0 +1,39 @@ +markTestSkipped( + 'TLS is not configured for your system. It is not possible to run this test' + ); + } + if (!defined('SWIFT_TLS_HOST')) { + $this->markTestSkipped( + 'Cannot run test without a TLS enabled SMTP host to connect to (define '. + 'SWIFT_TLS_HOST in tests/acceptance.conf.php if you wish to run this test)' + ); + } + parent::setUp(); + } + + protected function initializeBuffer() + { + $parts = explode(':', SWIFT_TLS_HOST); + $host = $parts[0]; + $port = isset($parts[1]) ? $parts[1] : 25; + + $this->buffer->initialize(array( + 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET, + 'host' => $host, + 'port' => $port, + 'protocol' => 'tls', + 'blocking' => 1, + 'timeout' => 15, + )); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bootstrap.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bootstrap.php new file mode 100644 index 00000000..27091a28 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bootstrap.php @@ -0,0 +1,21 @@ +allowMockingNonExistentMethods(true); + +if (is_file(__DIR__.'/acceptance.conf.php')) { + require_once __DIR__.'/acceptance.conf.php'; +} +if (is_file(__DIR__.'/smoke.conf.php')) { + require_once __DIR__.'/smoke.conf.php'; +} +require_once __DIR__.'/StreamCollector.php'; +require_once __DIR__.'/IdenticalBinaryConstraint.php'; +require_once __DIR__.'/SwiftMailerTestCase.php'; +require_once __DIR__.'/SwiftMailerSmokeTestCase.php'; diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug111Test.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug111Test.php new file mode 100644 index 00000000..9853f46e --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug111Test.php @@ -0,0 +1,42 @@ + array( + 'email1@example.com', + 'email2@example.com', + 'email3@example.com', + 'email4@example.com', + 'email5@example.com', + ), + 'sub' => array( + '-name-' => array( + 'email1', + '"email2"', + 'email3\\', + 'email4', + 'email5', + ), + '-url-' => array( + 'http://google.com', + 'http://yahoo.com', + 'http://hotmail.com', + 'http://aol.com', + 'http://facebook.com', + ), + ), + ); + $json = json_encode($complicated_header); + + $message = new Swift_Message(); + $headers = $message->getHeaders(); + $headers->addTextHeader('X-SMTPAPI', $json); + $header = $headers->get('X-SMTPAPI'); + + $this->assertEquals('Swift_Mime_Headers_UnstructuredHeader', get_class($header)); + $this->assertEquals($json, $header->getFieldBody()); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug118Test.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug118Test.php new file mode 100644 index 00000000..34aa1363 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug118Test.php @@ -0,0 +1,20 @@ +message = new Swift_Message(); + } + + public function testCallingGenerateIdChangesTheMessageId() + { + $currentId = $this->message->getId(); + $this->message->generateId(); + $newId = $this->message->getId(); + + $this->assertNotEquals($currentId, $newId); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug206Test.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug206Test.php new file mode 100644 index 00000000..02072e67 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug206Test.php @@ -0,0 +1,40 @@ +factory = new Swift_Mime_SimpleHeaderFactory($headerEncoder, $paramEncoder, $emailValidator); + } + + public function testMailboxHeaderEncoding() + { + $this->doTestHeaderIsFullyEncoded('email@example.org', 'Family Name, Name', ' "Family Name, Name" '); + $this->doTestHeaderIsFullyEncoded('email@example.org', 'Family Namé, Name', ' Family =?utf-8?Q?Nam=C3=A9=2C?= Name'); + $this->doTestHeaderIsFullyEncoded('email@example.org', 'Family Namé , Name', ' Family =?utf-8?Q?Nam=C3=A9_=2C?= Name'); + $this->doTestHeaderIsFullyEncoded('email@example.org', 'Family Namé ;Name', ' Family =?utf-8?Q?Nam=C3=A9_=3BName?= '); + } + + private function doTestHeaderIsFullyEncoded($email, $name, $expected) + { + $mailboxHeader = $this->factory->createMailboxHeader('To', array( + $email => $name, + )); + + $headerBody = substr($mailboxHeader->toString(), 3, strlen($expected)); + + $this->assertEquals($expected, $headerBody); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug274Test.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug274Test.php new file mode 100644 index 00000000..ddf6ca13 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug274Test.php @@ -0,0 +1,25 @@ +attach(Swift_Attachment::fromPath('')); + } + + public function testNonEmptyFileNameAsAttachment() + { + $message = new Swift_Message(); + try { + $message->attach(Swift_Attachment::fromPath(__FILE__)); + } catch (Exception $e) { + $this->fail('Path should not be empty'); + } + $this->addToAssertionCount(1); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug34Test.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug34Test.php new file mode 100644 index 00000000..158cf5a5 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug34Test.php @@ -0,0 +1,75 @@ +setCharset('utf-8'); + } + + public function testEmbeddedFilesWithMultipartDataCreateMultipartRelatedContentAsAnAlternative() + { + $message = new Swift_Message(); + $message->setCharset('utf-8'); + $message->setSubject('test subject'); + $message->addPart('plain part', 'text/plain'); + + $image = new Swift_Image('', 'image.gif', 'image/gif'); + $cid = $message->embed($image); + + $message->setBody('', 'text/html'); + + $message->setTo(array('user@domain.tld' => 'User')); + + $message->setFrom(array('other@domain.tld' => 'Other')); + $message->setSender(array('other@domain.tld' => 'Other')); + + $id = $message->getId(); + $date = preg_quote($message->getDate()->format('r'), '~'); + $boundary = $message->getBoundary(); + $cidVal = $image->getId(); + + $this->assertRegExp( + '~^'. + 'Sender: Other '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date."\r\n". + 'Subject: test subject'."\r\n". + 'From: Other '."\r\n". + 'To: User '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/alternative;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/plain; charset=utf-8'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'plain part'. + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: multipart/related;'."\r\n". + ' boundary="(.*?)"'."\r\n". + "\r\n\r\n". + '--\\1'."\r\n". + 'Content-Type: text/html; charset=utf-8'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + ''. + "\r\n\r\n". + '--\\1'."\r\n". + 'Content-Type: image/gif; name=image.gif'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-ID: <'.$cidVal.'>'."\r\n". + 'Content-Disposition: inline; filename=image.gif'."\r\n". + "\r\n". + preg_quote(base64_encode(''), '~'). + "\r\n\r\n". + '--\\1--'."\r\n". + "\r\n\r\n". + '--'.$boundary.'--'."\r\n". + '$~D', + $message->toString() + ); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug35Test.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug35Test.php new file mode 100644 index 00000000..f7835758 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug35Test.php @@ -0,0 +1,73 @@ +setCharset('utf-8'); + } + + public function testHTMLPartAppearsLastEvenWhenAttachmentsAdded() + { + $message = new Swift_Message(); + $message->setCharset('utf-8'); + $message->setSubject('test subject'); + $message->addPart('plain part', 'text/plain'); + + $attachment = new Swift_Attachment('', 'image.gif', 'image/gif'); + $message->attach($attachment); + + $message->setBody('HTML part', 'text/html'); + + $message->setTo(array('user@domain.tld' => 'User')); + + $message->setFrom(array('other@domain.tld' => 'Other')); + $message->setSender(array('other@domain.tld' => 'Other')); + + $id = $message->getId(); + $date = preg_quote($message->getDate()->format('r'), '~'); + $boundary = $message->getBoundary(); + + $this->assertRegExp( + '~^'. + 'Sender: Other '."\r\n". + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date."\r\n". + 'Subject: test subject'."\r\n". + 'From: Other '."\r\n". + 'To: User '."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/mixed;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: multipart/alternative;'."\r\n". + ' boundary="(.*?)"'."\r\n". + "\r\n\r\n". + '--\\1'."\r\n". + 'Content-Type: text/plain; charset=utf-8'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'plain part'. + "\r\n\r\n". + '--\\1'."\r\n". + 'Content-Type: text/html; charset=utf-8'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'HTML part'. + "\r\n\r\n". + '--\\1--'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: image/gif; name=image.gif'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-Disposition: attachment; filename=image.gif'."\r\n". + "\r\n". + preg_quote(base64_encode(''), '~'). + "\r\n\r\n". + '--'.$boundary.'--'."\r\n". + '$~D', + $message->toString() + ); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug38Test.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug38Test.php new file mode 100644 index 00000000..472c8058 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug38Test.php @@ -0,0 +1,192 @@ +attFileName = 'data.txt'; + $this->attFileType = 'text/plain'; + $this->attFile = __DIR__.'/../../_samples/files/data.txt'; + Swift_Preferences::getInstance()->setCharset('utf-8'); + } + + public function testWritingMessageToByteStreamProducesCorrectStructure() + { + $message = new Swift_Message(); + $message->setSubject('test subject'); + $message->setTo('user@domain.tld'); + $message->setCc('other@domain.tld'); + $message->setFrom('user@domain.tld'); + + $image = new Swift_Image('', 'image.gif', 'image/gif'); + + $cid = $message->embed($image); + $message->setBody('HTML part', 'text/html'); + + $id = $message->getId(); + $date = preg_quote($message->getDate()->format('r'), '~'); + $boundary = $message->getBoundary(); + $imgId = $image->getId(); + + $stream = new Swift_ByteStream_ArrayByteStream(); + + $message->toByteStream($stream); + + $this->assertPatternInStream( + '~^'. + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date."\r\n". + 'Subject: test subject'."\r\n". + 'From: user@domain.tld'."\r\n". + 'To: user@domain.tld'."\r\n". + 'Cc: other@domain.tld'."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/related;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/html; charset=utf-8'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'HTML part'. + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: image/gif; name=image.gif'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-ID: <'.preg_quote($imgId, '~').'>'."\r\n". + 'Content-Disposition: inline; filename=image.gif'."\r\n". + "\r\n". + preg_quote(base64_encode(''), '~'). + "\r\n\r\n". + '--'.$boundary.'--'."\r\n". + '$~D', + $stream + ); + } + + public function testWritingMessageToByteStreamTwiceProducesCorrectStructure() + { + $message = new Swift_Message(); + $message->setSubject('test subject'); + $message->setTo('user@domain.tld'); + $message->setCc('other@domain.tld'); + $message->setFrom('user@domain.tld'); + + $image = new Swift_Image('', 'image.gif', 'image/gif'); + + $cid = $message->embed($image); + $message->setBody('HTML part', 'text/html'); + + $id = $message->getId(); + $date = preg_quote($message->getDate()->format('r'), '~'); + $boundary = $message->getBoundary(); + $imgId = $image->getId(); + + $pattern = '~^'. + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date."\r\n". + 'Subject: test subject'."\r\n". + 'From: user@domain.tld'."\r\n". + 'To: user@domain.tld'."\r\n". + 'Cc: other@domain.tld'."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/related;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/html; charset=utf-8'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'HTML part'. + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: image/gif; name=image.gif'."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-ID: <'.preg_quote($imgId, '~').'>'."\r\n". + 'Content-Disposition: inline; filename=image.gif'."\r\n". + "\r\n". + preg_quote(base64_encode(''), '~'). + "\r\n\r\n". + '--'.$boundary.'--'."\r\n". + '$~D' + ; + + $streamA = new Swift_ByteStream_ArrayByteStream(); + $streamB = new Swift_ByteStream_ArrayByteStream(); + + $message->toByteStream($streamA); + $message->toByteStream($streamB); + + $this->assertPatternInStream($pattern, $streamA); + $this->assertPatternInStream($pattern, $streamB); + } + + public function testWritingMessageToByteStreamTwiceUsingAFileAttachment() + { + $message = new Swift_Message(); + $message->setSubject('test subject'); + $message->setTo('user@domain.tld'); + $message->setCc('other@domain.tld'); + $message->setFrom('user@domain.tld'); + + $attachment = Swift_Attachment::fromPath($this->attFile); + + $message->attach($attachment); + + $message->setBody('HTML part', 'text/html'); + + $id = $message->getId(); + $date = preg_quote($message->getDate()->format('r'), '~'); + $boundary = $message->getBoundary(); + + $streamA = new Swift_ByteStream_ArrayByteStream(); + $streamB = new Swift_ByteStream_ArrayByteStream(); + + $pattern = '~^'. + 'Message-ID: <'.$id.'>'."\r\n". + 'Date: '.$date."\r\n". + 'Subject: test subject'."\r\n". + 'From: user@domain.tld'."\r\n". + 'To: user@domain.tld'."\r\n". + 'Cc: other@domain.tld'."\r\n". + 'MIME-Version: 1.0'."\r\n". + 'Content-Type: multipart/mixed;'."\r\n". + ' boundary="'.$boundary.'"'."\r\n". + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: text/html; charset=utf-8'."\r\n". + 'Content-Transfer-Encoding: quoted-printable'."\r\n". + "\r\n". + 'HTML part'. + "\r\n\r\n". + '--'.$boundary."\r\n". + 'Content-Type: '.$this->attFileType.'; name='.$this->attFileName."\r\n". + 'Content-Transfer-Encoding: base64'."\r\n". + 'Content-Disposition: attachment; filename='.$this->attFileName."\r\n". + "\r\n". + preg_quote(base64_encode(file_get_contents($this->attFile)), '~'). + "\r\n\r\n". + '--'.$boundary.'--'."\r\n". + '$~D' + ; + + $message->toByteStream($streamA); + $message->toByteStream($streamB); + + $this->assertPatternInStream($pattern, $streamA); + $this->assertPatternInStream($pattern, $streamB); + } + + public function assertPatternInStream($pattern, $stream, $message = '%s') + { + $string = ''; + while (false !== $bytes = $stream->read(8192)) { + $string .= $bytes; + } + $this->assertRegExp($pattern, $string, $message); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug518Test.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug518Test.php new file mode 100644 index 00000000..e4d1d7c0 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug518Test.php @@ -0,0 +1,38 @@ +setTo('foo@bar.com'); + + $that = $this; + $messageValidation = function ($m) use ($that) { + //the getTo should return the same value as we put in + $that->assertEquals('foo@bar.com', key($m->getTo()), 'The message has changed after it was put to the memory queue'); + + return true; + }; + + $transport = m::mock('Swift_Transport'); + $transport->shouldReceive('isStarted')->andReturn(true); + $transport->shouldReceive('send') + ->with(m::on($messageValidation), $failedRecipients) + ->andReturn(1); + + $memorySpool = new Swift_MemorySpool(); + $memorySpool->queueMessage($message); + + /* + * The message is queued in memory. + * Lets change the message + */ + $message->setTo('other@value.com'); + + $memorySpool->flushQueue($transport, $failedRecipients); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug51Test.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug51Test.php new file mode 100644 index 00000000..fdeb89b9 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug51Test.php @@ -0,0 +1,110 @@ +attachmentFile = sys_get_temp_dir().'/attach.rand.bin'; + file_put_contents($this->attachmentFile, ''); + + $this->outputFile = sys_get_temp_dir().'/attach.out.bin'; + file_put_contents($this->outputFile, ''); + } + + protected function tearDown() + { + unlink($this->attachmentFile); + unlink($this->outputFile); + } + + public function testAttachmentsDoNotGetTruncatedUsingToByteStream() + { + //Run 100 times with 10KB attachments + for ($i = 0; $i < 10; ++$i) { + $message = $this->createMessageWithRandomAttachment( + 10000, $this->attachmentFile + ); + + file_put_contents($this->outputFile, ''); + $message->toByteStream( + new Swift_ByteStream_FileByteStream($this->outputFile, true) + ); + + $emailSource = file_get_contents($this->outputFile); + + $this->assertAttachmentFromSourceMatches( + file_get_contents($this->attachmentFile), + $emailSource + ); + } + } + + public function testAttachmentsDoNotGetTruncatedUsingToString() + { + //Run 100 times with 10KB attachments + for ($i = 0; $i < 10; ++$i) { + $message = $this->createMessageWithRandomAttachment( + 10000, $this->attachmentFile + ); + + $emailSource = $message->toString(); + + $this->assertAttachmentFromSourceMatches( + file_get_contents($this->attachmentFile), + $emailSource + ); + } + } + + public function assertAttachmentFromSourceMatches($attachmentData, $source) + { + $encHeader = 'Content-Transfer-Encoding: base64'; + $base64declaration = strpos($source, $encHeader); + + $attachmentDataStart = strpos($source, "\r\n\r\n", $base64declaration); + $attachmentDataEnd = strpos($source, "\r\n--", $attachmentDataStart); + + if (false === $attachmentDataEnd) { + $attachmentBase64 = trim(substr($source, $attachmentDataStart)); + } else { + $attachmentBase64 = trim(substr( + $source, $attachmentDataStart, + $attachmentDataEnd - $attachmentDataStart + )); + } + + $this->assertIdenticalBinary($attachmentData, base64_decode($attachmentBase64)); + } + + private function fillFileWithRandomBytes($byteCount, $file) + { + // I was going to use dd with if=/dev/random but this way seems more + // cross platform even if a hella expensive!! + + file_put_contents($file, ''); + $fp = fopen($file, 'wb'); + for ($i = 0; $i < $byteCount; ++$i) { + $byteVal = random_int(0, 255); + fwrite($fp, pack('i', $byteVal)); + } + fclose($fp); + } + + private function createMessageWithRandomAttachment($size, $attachmentPath) + { + $this->fillFileWithRandomBytes($size, $attachmentPath); + + $message = (new Swift_Message()) + ->setSubject('test') + ->setBody('test') + ->setFrom('a@b.c') + ->setTo('d@e.f') + ->attach(Swift_Attachment::fromPath($attachmentPath)) + ; + + return $message; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug534Test.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug534Test.php new file mode 100644 index 00000000..01f4af51 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug534Test.php @@ -0,0 +1,38 @@ +setFrom('from@example.com') + ->setTo('to@example.com') + ->setSubject('test') + ; + $cid = $message->embed(Swift_Image::fromPath(__DIR__.'/../../_samples/files/swiftmailer.png')); + $message->setBody('', 'text/html'); + + $that = $this; + $messageValidation = function (Swift_Mime_SimpleMessage $message) use ($that) { + preg_match('/cid:(.*)"/', $message->toString(), $matches); + $cid = $matches[1]; + preg_match('/Content-ID: <(.*)>/', $message->toString(), $matches); + $contentId = $matches[1]; + $that->assertEquals($cid, $contentId, 'cid in body and mime part Content-ID differ'); + + return true; + }; + + $failedRecipients = array(); + + $transport = m::mock('Swift_Transport'); + $transport->shouldReceive('isStarted')->andReturn(true); + $transport->shouldReceive('send')->with(m::on($messageValidation), $failedRecipients)->andReturn(1); + + $memorySpool = new Swift_MemorySpool(); + $memorySpool->queueMessage($message); + $memorySpool->flushQueue($transport, $failedRecipients); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug650Test.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug650Test.php new file mode 100644 index 00000000..e7cc65a0 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug650Test.php @@ -0,0 +1,38 @@ +setCharset('utf-8'); + + $header->setNameAddresses(array( + 'test@example.com' => $name, + )); + + $this->assertSame('To: '.$expectedEncodedName." \r\n", $header->toString()); + } + + public function encodingDataProvider() + { + return array( + array('this is " a test ö', 'this is =?utf-8?Q?=22?= a test =?utf-8?Q?=C3=B6?='), + array(': this is a test ö', '=?utf-8?Q?=3A?= this is a test =?utf-8?Q?=C3=B6?='), + array('( test ö', '=?utf-8?Q?=28?= test =?utf-8?Q?=C3=B6?='), + array('[ test ö', '=?utf-8?Q?=5B?= test =?utf-8?Q?=C3=B6?='), + array('@ test ö)', '=?utf-8?Q?=40?= test =?utf-8?Q?=C3=B6=29?='), + ); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug71Test.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug71Test.php new file mode 100644 index 00000000..3075f676 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug71Test.php @@ -0,0 +1,20 @@ +message = new Swift_Message('test'); + } + + public function testCallingToStringAfterSettingNewBodyReflectsChanges() + { + $this->message->setBody('BODY1'); + $this->assertRegExp('/BODY1/', $this->message->toString()); + + $this->message->setBody('BODY2'); + $this->assertRegExp('/BODY2/', $this->message->toString()); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug76Test.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug76Test.php new file mode 100644 index 00000000..1db20357 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/Bug76Test.php @@ -0,0 +1,71 @@ +inputFile = sys_get_temp_dir().'/in.bin'; + file_put_contents($this->inputFile, ''); + + $this->outputFile = sys_get_temp_dir().'/out.bin'; + file_put_contents($this->outputFile, ''); + + $this->encoder = $this->createEncoder(); + } + + protected function tearDown() + { + unlink($this->inputFile); + unlink($this->outputFile); + } + + public function testBase64EncodedLineLengthNeverExceeds76CharactersEvenIfArgsDo() + { + $this->fillFileWithRandomBytes(1000, $this->inputFile); + + $os = $this->createStream($this->inputFile); + $is = $this->createStream($this->outputFile); + + $this->encoder->encodeByteStream($os, $is, 0, 80); //Exceeds 76 + + $this->assertMaxLineLength(76, $this->outputFile, + '%s: Line length should not exceed 76 characters' + ); + } + + public function assertMaxLineLength($length, $filePath, $message = '%s') + { + $lines = file($filePath); + foreach ($lines as $line) { + $this->assertTrue((strlen(trim($line)) <= 76), $message); + } + } + + private function fillFileWithRandomBytes($byteCount, $file) + { + // I was going to use dd with if=/dev/random but this way seems more + // cross platform even if a hella expensive!! + + file_put_contents($file, ''); + $fp = fopen($file, 'wb'); + for ($i = 0; $i < $byteCount; ++$i) { + $byteVal = random_int(0, 255); + fwrite($fp, pack('i', $byteVal)); + } + fclose($fp); + } + + private function createEncoder() + { + return new Swift_Mime_ContentEncoder_Base64ContentEncoder(); + } + + private function createStream($file) + { + return new Swift_ByteStream_FileByteStream($file, true); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/BugFileByteStreamConsecutiveReadCallsTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/BugFileByteStreamConsecutiveReadCallsTest.php new file mode 100644 index 00000000..eb580719 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/bug/Swift/BugFileByteStreamConsecutiveReadCallsTest.php @@ -0,0 +1,18 @@ +read(100); + } catch (\Swift_IoException $exc) { + $fbs->read(100); + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/fixtures/MimeEntityFixture.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/fixtures/MimeEntityFixture.php new file mode 100644 index 00000000..8a660393 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/fixtures/MimeEntityFixture.php @@ -0,0 +1,67 @@ +level = $level; + $this->string = $string; + $this->contentType = $contentType; + } + + public function getNestingLevel() + { + return $this->level; + } + + public function toString() + { + return $this->string; + } + + public function getContentType() + { + return $this->contentType; + } + + // These methods are here to account for the implemented interfaces + public function getId() + { + } + + public function getHeaders() + { + } + + public function getBody() + { + } + + public function setBody($body, $contentType = null) + { + } + + public function toByteStream(Swift_InputByteStream $is) + { + } + + public function charsetChanged($charset) + { + } + + public function encoderChanged(Swift_Mime_ContentEncoder $encoder) + { + } + + public function getChildren() + { + } + + public function setChildren(array $children, $compoundLevel = null) + { + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke.conf.php.default b/lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke.conf.php.default new file mode 100644 index 00000000..604d6de7 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke.conf.php.default @@ -0,0 +1,63 @@ +attFile = __DIR__.'/../../../_samples/files/textfile.zip'; + } + + public function testAttachmentSending() + { + $mailer = $this->getMailer(); + $message = (new Swift_Message()) + ->setSubject('[Swift Mailer] AttachmentSmokeTest') + ->setFrom(array(SWIFT_SMOKE_EMAIL_ADDRESS => 'Swift Mailer')) + ->setTo(SWIFT_SMOKE_EMAIL_ADDRESS) + ->setBody('This message should contain an attached ZIP file (named "textfile.zip").'.PHP_EOL. + 'When unzipped, the archive should produce a text file which reads:'.PHP_EOL. + '"This is part of a Swift Mailer smoke test."' + ) + ->attach(Swift_Attachment::fromPath($this->attFile)) + ; + $this->assertEquals(1, $mailer->send($message), + '%s: The smoke test should send a single message' + ); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke/Swift/Smoke/BasicSmokeTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke/Swift/Smoke/BasicSmokeTest.php new file mode 100644 index 00000000..a0db5164 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke/Swift/Smoke/BasicSmokeTest.php @@ -0,0 +1,23 @@ +getMailer(); + $message = (new Swift_Message()) + ->setSubject('[Swift Mailer] BasicSmokeTest') + ->setFrom(array(SWIFT_SMOKE_EMAIL_ADDRESS => 'Swift Mailer')) + ->setTo(SWIFT_SMOKE_EMAIL_ADDRESS) + ->setBody('One, two, three, four, five...'.PHP_EOL. + 'six, seven, eight...' + ) + ; + $this->assertEquals(1, $mailer->send($message), + '%s: The smoke test should send a single message' + ); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke/Swift/Smoke/HtmlWithAttachmentSmokeTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke/Swift/Smoke/HtmlWithAttachmentSmokeTest.php new file mode 100644 index 00000000..7b3d8940 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke/Swift/Smoke/HtmlWithAttachmentSmokeTest.php @@ -0,0 +1,31 @@ +attFile = __DIR__.'/../../../_samples/files/textfile.zip'; + } + + public function testAttachmentSending() + { + $mailer = $this->getMailer(); + $message = (new Swift_Message('[Swift Mailer] HtmlWithAttachmentSmokeTest')) + ->setFrom(array(SWIFT_SMOKE_EMAIL_ADDRESS => 'Swift Mailer')) + ->setTo(SWIFT_SMOKE_EMAIL_ADDRESS) + ->attach(Swift_Attachment::fromPath($this->attFile)) + ->setBody('

This HTML-formatted message should contain an attached ZIP file (named "textfile.zip").'.PHP_EOL. + 'When unzipped, the archive should produce a text file which reads:

'.PHP_EOL. + '

This is part of a Swift Mailer smoke test.

', 'text/html' + ) + ; + $this->assertEquals(1, $mailer->send($message), + '%s: The smoke test should send a single message' + ); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke/Swift/Smoke/InternationalSmokeTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke/Swift/Smoke/InternationalSmokeTest.php new file mode 100644 index 00000000..c47ddd2a --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/smoke/Swift/Smoke/InternationalSmokeTest.php @@ -0,0 +1,40 @@ +attFile = __DIR__.'/../../../_samples/files/textfile.zip'; + } + + public function testAttachmentSending() + { + $mailer = $this->getMailer(); + $message = (new Swift_Message()) + ->setCharset('utf-8') + ->setSubject('[Swift Mailer] InternationalSmokeTest (διεθνής)') + ->setFrom(array(SWIFT_SMOKE_EMAIL_ADDRESS => 'Χριστοφορου (Swift Mailer)')) + ->setTo(SWIFT_SMOKE_EMAIL_ADDRESS) + ->setBody('This message should contain an attached ZIP file (named "κείμενο, εδάφιο, θέμα.zip").'.PHP_EOL. + 'When unzipped, the archive should produce a text file which reads:'.PHP_EOL. + '"This is part of a Swift Mailer smoke test."'.PHP_EOL. + PHP_EOL. + 'Following is some arbitrary Greek text:'.PHP_EOL. + 'Δεν βρέθηκαν λέξεις.' + ) + ->attach(Swift_Attachment::fromPath($this->attFile) + ->setContentType('application/zip') + ->setFilename('κείμενο, εδάφιο, θέμα.zip') + ) + ; + $this->assertEquals(1, $mailer->send($message), + '%s: The smoke test should send a single message' + ); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/ByteStream/ArrayByteStreamTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/ByteStream/ArrayByteStreamTest.php new file mode 100644 index 00000000..4da0da70 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/ByteStream/ArrayByteStreamTest.php @@ -0,0 +1,202 @@ +createArrayStream($input); + $output = array(); + while (false !== $bytes = $bs->read(1)) { + $output[] = $bytes; + } + $this->assertEquals($input, $output, + '%s: Bytes read from stream should be the same as bytes in constructor' + ); + } + + public function testReadingMultipleBytesFromBaseInput() + { + $input = array('a', 'b', 'c', 'd'); + $bs = $this->createArrayStream($input); + $output = array(); + while (false !== $bytes = $bs->read(2)) { + $output[] = $bytes; + } + $this->assertEquals(array('ab', 'cd'), $output, + '%s: Bytes read from stream should be in pairs' + ); + } + + public function testReadingOddOffsetOnLastByte() + { + $input = array('a', 'b', 'c', 'd', 'e'); + $bs = $this->createArrayStream($input); + $output = array(); + while (false !== $bytes = $bs->read(2)) { + $output[] = $bytes; + } + $this->assertEquals(array('ab', 'cd', 'e'), $output, + '%s: Bytes read from stream should be in pairs except final read' + ); + } + + public function testSettingPointerPartway() + { + $input = array('a', 'b', 'c'); + $bs = $this->createArrayStream($input); + $bs->setReadPointer(1); + $this->assertEquals('b', $bs->read(1), + '%s: Byte should be second byte since pointer as at offset 1' + ); + } + + public function testResettingPointerAfterExhaustion() + { + $input = array('a', 'b', 'c'); + + $bs = $this->createArrayStream($input); + while (false !== $bs->read(1)); + + $bs->setReadPointer(0); + $this->assertEquals('a', $bs->read(1), + '%s: Byte should be first byte since pointer as at offset 0' + ); + } + + public function testPointerNeverSetsBelowZero() + { + $input = array('a', 'b', 'c'); + $bs = $this->createArrayStream($input); + + $bs->setReadPointer(-1); + $this->assertEquals('a', $bs->read(1), + '%s: Byte should be first byte since pointer should be at offset 0' + ); + } + + public function testPointerNeverSetsAboveStackSize() + { + $input = array('a', 'b', 'c'); + $bs = $this->createArrayStream($input); + + $bs->setReadPointer(3); + $this->assertFalse($bs->read(1), + '%s: Stream should be at end and thus return false' + ); + } + + public function testBytesCanBeWrittenToStream() + { + $input = array('a', 'b', 'c'); + $bs = $this->createArrayStream($input); + + $bs->write('de'); + + $output = array(); + while (false !== $bytes = $bs->read(1)) { + $output[] = $bytes; + } + $this->assertEquals(array('a', 'b', 'c', 'd', 'e'), $output, + '%s: Bytes read from stream should be from initial stack + written' + ); + } + + public function testContentsCanBeFlushed() + { + $input = array('a', 'b', 'c'); + $bs = $this->createArrayStream($input); + + $bs->flushBuffers(); + + $this->assertFalse($bs->read(1), + '%s: Contents have been flushed so read() should return false' + ); + } + + public function testConstructorCanTakeStringArgument() + { + $bs = $this->createArrayStream('abc'); + $output = array(); + while (false !== $bytes = $bs->read(1)) { + $output[] = $bytes; + } + $this->assertEquals(array('a', 'b', 'c'), $output, + '%s: Bytes read from stream should be the same as bytes in constructor' + ); + } + + public function testBindingOtherStreamsMirrorsWriteOperations() + { + $bs = $this->createArrayStream(''); + $is1 = $this->getMockBuilder('Swift_InputByteStream')->getMock(); + $is2 = $this->getMockBuilder('Swift_InputByteStream')->getMock(); + + $is1->expects($this->at(0)) + ->method('write') + ->with('x'); + $is1->expects($this->at(1)) + ->method('write') + ->with('y'); + $is2->expects($this->at(0)) + ->method('write') + ->with('x'); + $is2->expects($this->at(1)) + ->method('write') + ->with('y'); + + $bs->bind($is1); + $bs->bind($is2); + + $bs->write('x'); + $bs->write('y'); + } + + public function testBindingOtherStreamsMirrorsFlushOperations() + { + $bs = $this->createArrayStream(''); + $is1 = $this->getMockBuilder('Swift_InputByteStream')->getMock(); + $is2 = $this->getMockBuilder('Swift_InputByteStream')->getMock(); + + $is1->expects($this->once()) + ->method('flushBuffers'); + $is2->expects($this->once()) + ->method('flushBuffers'); + + $bs->bind($is1); + $bs->bind($is2); + + $bs->flushBuffers(); + } + + public function testUnbindingStreamPreventsFurtherWrites() + { + $bs = $this->createArrayStream(''); + $is1 = $this->getMockBuilder('Swift_InputByteStream')->getMock(); + $is2 = $this->getMockBuilder('Swift_InputByteStream')->getMock(); + + $is1->expects($this->at(0)) + ->method('write') + ->with('x'); + $is1->expects($this->at(1)) + ->method('write') + ->with('y'); + $is2->expects($this->once()) + ->method('write') + ->with('x'); + + $bs->bind($is1); + $bs->bind($is2); + + $bs->write('x'); + + $bs->unbind($is2); + + $bs->write('y'); + } + + private function createArrayStream($input) + { + return new Swift_ByteStream_ArrayByteStream($input); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterReader/GenericFixedWidthReaderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterReader/GenericFixedWidthReaderTest.php new file mode 100644 index 00000000..659b3c88 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterReader/GenericFixedWidthReaderTest.php @@ -0,0 +1,43 @@ +assertSame(1, $reader->getInitialByteSize()); + + $reader = new Swift_CharacterReader_GenericFixedWidthReader(4); + $this->assertSame(4, $reader->getInitialByteSize()); + } + + public function testValidationValueIsBasedOnOctetCount() + { + $reader = new Swift_CharacterReader_GenericFixedWidthReader(4); + + $this->assertSame( + 1, $reader->validateByteSequence(array(0x01, 0x02, 0x03), 3) + ); //3 octets + + $this->assertSame( + 2, $reader->validateByteSequence(array(0x01, 0x0A), 2) + ); //2 octets + + $this->assertSame( + 3, $reader->validateByteSequence(array(0xFE), 1) + ); //1 octet + + $this->assertSame( + 0, $reader->validateByteSequence(array(0xFE, 0x03, 0x67, 0x9A), 4) + ); //All 4 octets + } + + public function testValidationFailsIfTooManyOctets() + { + $reader = new Swift_CharacterReader_GenericFixedWidthReader(6); + + $this->assertSame(-1, $reader->validateByteSequence( + array(0xFE, 0x03, 0x67, 0x9A, 0x10, 0x09, 0x85), 7 + )); //7 octets + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterReader/UsAsciiReaderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterReader/UsAsciiReaderTest.php new file mode 100644 index 00000000..274cbdab --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterReader/UsAsciiReaderTest.php @@ -0,0 +1,52 @@ +read($size); ) { + $c .= $bytes; + $size = $v->validateCharacter($c); + if (-1 == $size) { + throw new Exception( ... invalid char .. ); + } elseif (0 == $size) { + return $c; //next character in $os + } + } + + */ + + private $reader; + + protected function setUp() + { + $this->reader = new Swift_CharacterReader_UsAsciiReader(); + } + + public function testAllValidAsciiCharactersReturnZero() + { + for ($ordinal = 0x00; $ordinal <= 0x7F; ++$ordinal) { + $this->assertSame( + 0, $this->reader->validateByteSequence(array($ordinal), 1) + ); + } + } + + public function testMultipleBytesAreInvalid() + { + for ($ordinal = 0x00; $ordinal <= 0x7F; $ordinal += 2) { + $this->assertSame( + -1, $this->reader->validateByteSequence(array($ordinal, $ordinal + 1), 2) + ); + } + } + + public function testBytesAboveAsciiRangeAreInvalid() + { + for ($ordinal = 0x80; $ordinal <= 0xFF; ++$ordinal) { + $this->assertSame( + -1, $this->reader->validateByteSequence(array($ordinal), 1) + ); + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterReader/Utf8ReaderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterReader/Utf8ReaderTest.php new file mode 100644 index 00000000..e28cf0ee --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterReader/Utf8ReaderTest.php @@ -0,0 +1,65 @@ +reader = new Swift_CharacterReader_Utf8Reader(); + } + + public function testLeading7BitOctetCausesReturnZero() + { + for ($ordinal = 0x00; $ordinal <= 0x7F; ++$ordinal) { + $this->assertSame( + 0, $this->reader->validateByteSequence(array($ordinal), 1) + ); + } + } + + public function testLeadingByteOf2OctetCharCausesReturn1() + { + for ($octet = 0xC0; $octet <= 0xDF; ++$octet) { + $this->assertSame( + 1, $this->reader->validateByteSequence(array($octet), 1) + ); + } + } + + public function testLeadingByteOf3OctetCharCausesReturn2() + { + for ($octet = 0xE0; $octet <= 0xEF; ++$octet) { + $this->assertSame( + 2, $this->reader->validateByteSequence(array($octet), 1) + ); + } + } + + public function testLeadingByteOf4OctetCharCausesReturn3() + { + for ($octet = 0xF0; $octet <= 0xF7; ++$octet) { + $this->assertSame( + 3, $this->reader->validateByteSequence(array($octet), 1) + ); + } + } + + public function testLeadingByteOf5OctetCharCausesReturn4() + { + for ($octet = 0xF8; $octet <= 0xFB; ++$octet) { + $this->assertSame( + 4, $this->reader->validateByteSequence(array($octet), 1) + ); + } + } + + public function testLeadingByteOf6OctetCharCausesReturn5() + { + for ($octet = 0xFC; $octet <= 0xFD; ++$octet) { + $this->assertSame( + 5, $this->reader->validateByteSequence(array($octet), 1) + ); + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterStream/ArrayCharacterStreamTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterStream/ArrayCharacterStreamTest.php new file mode 100644 index 00000000..8a5c64ae --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/CharacterStream/ArrayCharacterStreamTest.php @@ -0,0 +1,358 @@ +getReader(); + $factory = $this->getFactory($reader); + + $stream = new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8'); + + $reader->shouldReceive('getInitialByteSize') + ->zeroOrMoreTimes() + ->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD1), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + + $stream->importString(pack('C*', + 0xD0, 0x94, + 0xD0, 0xB6, + 0xD0, 0xBE, + 0xD1, 0x8D, + 0xD0, 0xBB, + 0xD0, 0xB0 + ) + ); + } + + public function testCharactersWrittenUseValidator() + { + $reader = $this->getReader(); + $factory = $this->getFactory($reader); + + $stream = new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8'); + + $reader->shouldReceive('getInitialByteSize') + ->zeroOrMoreTimes() + ->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD1), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD1), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD1), 1)->andReturn(1); + + $stream->importString(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + + $stream->write(pack('C*', + 0xD0, 0xBB, + 0xD1, 0x8E, + 0xD0, 0xB1, + 0xD1, 0x8B, + 0xD1, 0x85 + ) + ); + } + + public function testReadCharactersAreInTact() + { + $reader = $this->getReader(); + $factory = $this->getFactory($reader); + + $stream = new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8'); + + $reader->shouldReceive('getInitialByteSize') + ->zeroOrMoreTimes() + ->andReturn(1); + //String + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + //Stream + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD1), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD1), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD1), 1)->andReturn(1); + + $stream->importString(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + + $stream->write(pack('C*', + 0xD0, 0xBB, + 0xD1, 0x8E, + 0xD0, 0xB1, + 0xD1, 0x8B, + 0xD1, 0x85 + ) + ); + + $this->assertIdenticalBinary(pack('C*', 0xD0, 0x94), $stream->read(1)); + $this->assertIdenticalBinary( + pack('C*', 0xD0, 0xB6, 0xD0, 0xBE), $stream->read(2) + ); + $this->assertIdenticalBinary(pack('C*', 0xD0, 0xBB), $stream->read(1)); + $this->assertIdenticalBinary( + pack('C*', 0xD1, 0x8E, 0xD0, 0xB1, 0xD1, 0x8B), $stream->read(3) + ); + $this->assertIdenticalBinary(pack('C*', 0xD1, 0x85), $stream->read(1)); + + $this->assertFalse($stream->read(1)); + } + + public function testCharactersCanBeReadAsByteArrays() + { + $reader = $this->getReader(); + $factory = $this->getFactory($reader); + + $stream = new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8'); + + $reader->shouldReceive('getInitialByteSize') + ->zeroOrMoreTimes() + ->andReturn(1); + //String + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + //Stream + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD1), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD1), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD1), 1)->andReturn(1); + + $stream->importString(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + + $stream->write(pack('C*', + 0xD0, 0xBB, + 0xD1, 0x8E, + 0xD0, 0xB1, + 0xD1, 0x8B, + 0xD1, 0x85 + ) + ); + + $this->assertEquals(array(0xD0, 0x94), $stream->readBytes(1)); + $this->assertEquals(array(0xD0, 0xB6, 0xD0, 0xBE), $stream->readBytes(2)); + $this->assertEquals(array(0xD0, 0xBB), $stream->readBytes(1)); + $this->assertEquals( + array(0xD1, 0x8E, 0xD0, 0xB1, 0xD1, 0x8B), $stream->readBytes(3) + ); + $this->assertEquals(array(0xD1, 0x85), $stream->readBytes(1)); + + $this->assertFalse($stream->readBytes(1)); + } + + public function testRequestingLargeCharCountPastEndOfStream() + { + $reader = $this->getReader(); + $factory = $this->getFactory($reader); + + $stream = new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8'); + + $reader->shouldReceive('getInitialByteSize') + ->zeroOrMoreTimes() + ->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + + $stream->importString(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + + $this->assertIdenticalBinary(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE), + $stream->read(100) + ); + + $this->assertFalse($stream->read(1)); + } + + public function testRequestingByteArrayCountPastEndOfStream() + { + $reader = $this->getReader(); + $factory = $this->getFactory($reader); + + $stream = new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8'); + + $reader->shouldReceive('getInitialByteSize') + ->zeroOrMoreTimes() + ->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + + $stream->importString(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + + $this->assertEquals(array(0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE), + $stream->readBytes(100) + ); + + $this->assertFalse($stream->readBytes(1)); + } + + public function testPointerOffsetCanBeSet() + { + $reader = $this->getReader(); + $factory = $this->getFactory($reader); + + $stream = new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8'); + + $reader->shouldReceive('getInitialByteSize') + ->zeroOrMoreTimes() + ->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + + $stream->importString(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + + $this->assertIdenticalBinary(pack('C*', 0xD0, 0x94), $stream->read(1)); + + $stream->setPointer(0); + + $this->assertIdenticalBinary(pack('C*', 0xD0, 0x94), $stream->read(1)); + + $stream->setPointer(2); + + $this->assertIdenticalBinary(pack('C*', 0xD0, 0xBE), $stream->read(1)); + } + + public function testContentsCanBeFlushed() + { + $reader = $this->getReader(); + $factory = $this->getFactory($reader); + + $stream = new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8'); + + $reader->shouldReceive('getInitialByteSize') + ->zeroOrMoreTimes() + ->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + + $stream->importString(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + + $stream->flushContents(); + + $this->assertFalse($stream->read(1)); + } + + public function testByteStreamCanBeImportingUsesValidator() + { + $reader = $this->getReader(); + $factory = $this->getFactory($reader); + $os = $this->getByteStream(); + + $stream = new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8'); + + $os->shouldReceive('setReadPointer') + ->between(0, 1) + ->with(0); + $os->shouldReceive('read')->once()->andReturn(pack('C*', 0xD0)); + $os->shouldReceive('read')->once()->andReturn(pack('C*', 0x94)); + $os->shouldReceive('read')->once()->andReturn(pack('C*', 0xD0)); + $os->shouldReceive('read')->once()->andReturn(pack('C*', 0xB6)); + $os->shouldReceive('read')->once()->andReturn(pack('C*', 0xD0)); + $os->shouldReceive('read')->once()->andReturn(pack('C*', 0xBE)); + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturn(false); + + $reader->shouldReceive('getInitialByteSize') + ->zeroOrMoreTimes() + ->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + + $stream->importByteStream($os); + } + + public function testImportingStreamProducesCorrectCharArray() + { + $reader = $this->getReader(); + $factory = $this->getFactory($reader); + $os = $this->getByteStream(); + + $stream = new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8'); + + $os->shouldReceive('setReadPointer') + ->between(0, 1) + ->with(0); + $os->shouldReceive('read')->once()->andReturn(pack('C*', 0xD0)); + $os->shouldReceive('read')->once()->andReturn(pack('C*', 0x94)); + $os->shouldReceive('read')->once()->andReturn(pack('C*', 0xD0)); + $os->shouldReceive('read')->once()->andReturn(pack('C*', 0xB6)); + $os->shouldReceive('read')->once()->andReturn(pack('C*', 0xD0)); + $os->shouldReceive('read')->once()->andReturn(pack('C*', 0xBE)); + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturn(false); + + $reader->shouldReceive('getInitialByteSize') + ->zeroOrMoreTimes() + ->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0), 1)->andReturn(1); + + $stream->importByteStream($os); + + $this->assertIdenticalBinary(pack('C*', 0xD0, 0x94), $stream->read(1)); + $this->assertIdenticalBinary(pack('C*', 0xD0, 0xB6), $stream->read(1)); + $this->assertIdenticalBinary(pack('C*', 0xD0, 0xBE), $stream->read(1)); + + $this->assertFalse($stream->read(1)); + } + + public function testAlgorithmWithFixedWidthCharsets() + { + $reader = $this->getReader(); + $factory = $this->getFactory($reader); + + $reader->shouldReceive('getInitialByteSize') + ->zeroOrMoreTimes() + ->andReturn(2); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD1, 0x8D), 2); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0, 0xBB), 2); + $reader->shouldReceive('validateByteSequence')->once()->with(array(0xD0, 0xB0), 2); + + $stream = new Swift_CharacterStream_ArrayCharacterStream( + $factory, 'utf-8' + ); + $stream->importString(pack('C*', 0xD1, 0x8D, 0xD0, 0xBB, 0xD0, 0xB0)); + + $this->assertIdenticalBinary(pack('C*', 0xD1, 0x8D), $stream->read(1)); + $this->assertIdenticalBinary(pack('C*', 0xD0, 0xBB), $stream->read(1)); + $this->assertIdenticalBinary(pack('C*', 0xD0, 0xB0), $stream->read(1)); + + $this->assertFalse($stream->read(1)); + } + + private function getReader() + { + return $this->getMockery('Swift_CharacterReader'); + } + + private function getFactory($reader) + { + $factory = $this->getMockery('Swift_CharacterReaderFactory'); + $factory->shouldReceive('getReaderFor') + ->zeroOrMoreTimes() + ->with('utf-8') + ->andReturn($reader); + + return $factory; + } + + private function getByteStream() + { + return $this->getMockery('Swift_OutputByteStream'); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/DependencyContainerTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/DependencyContainerTest.php new file mode 100644 index 00000000..7b8c87ba --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/DependencyContainerTest.php @@ -0,0 +1,176 @@ +arg1 = $arg1; + $this->arg2 = $arg2; + } +} + +class Swift_DependencyContainerTest extends \PHPUnit\Framework\TestCase +{ + private $container; + + protected function setUp() + { + $this->container = new Swift_DependencyContainer(); + } + + public function testRegisterAndLookupValue() + { + $this->container->register('foo')->asValue('bar'); + $this->assertEquals('bar', $this->container->lookup('foo')); + } + + public function testHasReturnsTrueForRegisteredValue() + { + $this->container->register('foo')->asValue('bar'); + $this->assertTrue($this->container->has('foo')); + } + + public function testHasReturnsFalseForUnregisteredValue() + { + $this->assertFalse($this->container->has('foo')); + } + + public function testRegisterAndLookupNewInstance() + { + $this->container->register('one')->asNewInstanceOf('One'); + $this->assertInstanceOf('One', $this->container->lookup('one')); + } + + public function testHasReturnsTrueForRegisteredInstance() + { + $this->container->register('one')->asNewInstanceOf('One'); + $this->assertTrue($this->container->has('one')); + } + + public function testNewInstanceIsAlwaysNew() + { + $this->container->register('one')->asNewInstanceOf('One'); + $a = $this->container->lookup('one'); + $b = $this->container->lookup('one'); + $this->assertEquals($a, $b); + } + + public function testRegisterAndLookupSharedInstance() + { + $this->container->register('one')->asSharedInstanceOf('One'); + $this->assertInstanceOf('One', $this->container->lookup('one')); + } + + public function testHasReturnsTrueForSharedInstance() + { + $this->container->register('one')->asSharedInstanceOf('One'); + $this->assertTrue($this->container->has('one')); + } + + public function testMultipleSharedInstancesAreSameInstance() + { + $this->container->register('one')->asSharedInstanceOf('One'); + $a = $this->container->lookup('one'); + $b = $this->container->lookup('one'); + $this->assertEquals($a, $b); + } + + public function testNewInstanceWithDependencies() + { + $this->container->register('foo')->asValue('FOO'); + $this->container->register('one')->asNewInstanceOf('One') + ->withDependencies(array('foo')); + $obj = $this->container->lookup('one'); + $this->assertSame('FOO', $obj->arg1); + } + + public function testNewInstanceWithMultipleDependencies() + { + $this->container->register('foo')->asValue('FOO'); + $this->container->register('bar')->asValue(42); + $this->container->register('one')->asNewInstanceOf('One') + ->withDependencies(array('foo', 'bar')); + $obj = $this->container->lookup('one'); + $this->assertSame('FOO', $obj->arg1); + $this->assertSame(42, $obj->arg2); + } + + public function testNewInstanceWithInjectedObjects() + { + $this->container->register('foo')->asValue('FOO'); + $this->container->register('one')->asNewInstanceOf('One'); + $this->container->register('two')->asNewInstanceOf('One') + ->withDependencies(array('one', 'foo')); + $obj = $this->container->lookup('two'); + $this->assertEquals($this->container->lookup('one'), $obj->arg1); + $this->assertSame('FOO', $obj->arg2); + } + + public function testNewInstanceWithAddConstructorValue() + { + $this->container->register('one')->asNewInstanceOf('One') + ->addConstructorValue('x') + ->addConstructorValue(99); + $obj = $this->container->lookup('one'); + $this->assertSame('x', $obj->arg1); + $this->assertSame(99, $obj->arg2); + } + + public function testNewInstanceWithAddConstructorLookup() + { + $this->container->register('foo')->asValue('FOO'); + $this->container->register('bar')->asValue(42); + $this->container->register('one')->asNewInstanceOf('One') + ->addConstructorLookup('foo') + ->addConstructorLookup('bar'); + + $obj = $this->container->lookup('one'); + $this->assertSame('FOO', $obj->arg1); + $this->assertSame(42, $obj->arg2); + } + + public function testResolvedDependenciesCanBeLookedUp() + { + $this->container->register('foo')->asValue('FOO'); + $this->container->register('one')->asNewInstanceOf('One'); + $this->container->register('two')->asNewInstanceOf('One') + ->withDependencies(array('one', 'foo')); + $deps = $this->container->createDependenciesFor('two'); + $this->assertEquals( + array($this->container->lookup('one'), 'FOO'), $deps + ); + } + + public function testArrayOfDependenciesCanBeSpecified() + { + $this->container->register('foo')->asValue('FOO'); + $this->container->register('one')->asNewInstanceOf('One'); + $this->container->register('two')->asNewInstanceOf('One') + ->withDependencies(array(array('one', 'foo'), 'foo')); + + $obj = $this->container->lookup('two'); + $this->assertEquals(array($this->container->lookup('one'), 'FOO'), $obj->arg1); + $this->assertSame('FOO', $obj->arg2); + } + + public function testAliasCanBeSet() + { + $this->container->register('foo')->asValue('FOO'); + $this->container->register('bar')->asAliasOf('foo'); + + $this->assertSame('FOO', $this->container->lookup('bar')); + } + + public function testAliasOfAliasCanBeSet() + { + $this->container->register('foo')->asValue('FOO'); + $this->container->register('bar')->asAliasOf('foo'); + $this->container->register('zip')->asAliasOf('bar'); + $this->container->register('button')->asAliasOf('zip'); + + $this->assertSame('FOO', $this->container->lookup('button')); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Encoder/Base64EncoderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Encoder/Base64EncoderTest.php new file mode 100644 index 00000000..6387bad3 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Encoder/Base64EncoderTest.php @@ -0,0 +1,173 @@ +encoder = new Swift_Encoder_Base64Encoder(); + } + + /* + There's really no point in testing the entire base64 encoding to the + level QP encoding has been tested. base64_encode() has been in PHP for + years. + */ + + public function testInputOutputRatioIs3to4Bytes() + { + /* + RFC 2045, 6.8 + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + */ + + $this->assertEquals( + 'MTIz', $this->encoder->encodeString('123'), + '%s: 3 bytes of input should yield 4 bytes of output' + ); + $this->assertEquals( + 'MTIzNDU2', $this->encoder->encodeString('123456'), + '%s: 6 bytes in input should yield 8 bytes of output' + ); + $this->assertEquals( + 'MTIzNDU2Nzg5', $this->encoder->encodeString('123456789'), + '%s: 9 bytes in input should yield 12 bytes of output' + ); + } + + public function testPadLength() + { + /* + RFC 2045, 6.8 + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a body. When fewer than 24 input bits + are available in an input group, zero bits are added (on the right) + to form an integral number of 6-bit groups. Padding at the end of + the data is performed using the "=" character. Since all base64 + input is an integral number of octets, only the following cases can + arise: (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded output will be + an integral multiple of 4 characters with no "=" padding, (2) the + final quantum of encoding input is exactly 8 bits; here, the final + unit of encoded output will be two characters followed by two "=" + padding characters, or (3) the final quantum of encoding input is + exactly 16 bits; here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + + for ($i = 0; $i < 30; ++$i) { + $input = pack('C', random_int(0, 255)); + $this->assertRegExp( + '~^[a-zA-Z0-9/\+]{2}==$~', $this->encoder->encodeString($input), + '%s: A single byte should have 2 bytes of padding' + ); + } + + for ($i = 0; $i < 30; ++$i) { + $input = pack('C*', random_int(0, 255), random_int(0, 255)); + $this->assertRegExp( + '~^[a-zA-Z0-9/\+]{3}=$~', $this->encoder->encodeString($input), + '%s: Two bytes should have 1 byte of padding' + ); + } + + for ($i = 0; $i < 30; ++$i) { + $input = pack('C*', random_int(0, 255), random_int(0, 255), random_int(0, 255)); + $this->assertRegExp( + '~^[a-zA-Z0-9/\+]{4}$~', $this->encoder->encodeString($input), + '%s: Three bytes should have no padding' + ); + } + } + + public function testMaximumLineLengthIs76Characters() + { + /* + The encoded output stream must be represented in lines of no more + than 76 characters each. All line breaks or other characters not + found in Table 1 must be ignored by decoding software. + */ + + $input = + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + $output = + 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQk'.//38 + 'NERUZHSElKS0xNTk9QUVJTVFVWV1hZWjEyMzQ1'."\r\n".//76 * + 'Njc4OTBhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3'.//38 + 'h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFla'."\r\n".//76 * + 'MTIzNDU2Nzg5MEFCQ0RFRkdISUpLTE1OT1BRUl'.//38 + 'NUVVZXWFla'; //48 + + $this->assertEquals( + $output, $this->encoder->encodeString($input), + '%s: Lines should be no more than 76 characters' + ); + } + + public function testMaximumLineLengthCanBeSpecified() + { + $input = + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + $output = + 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQk'.//38 + 'NERUZHSElKS0'."\r\n".//50 * + 'xNTk9QUVJTVFVWV1hZWjEyMzQ1Njc4OTBhYmNk'.//38 + 'ZWZnaGlqa2xt'."\r\n".//50 * + 'bm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1'.//38 + 'BRUlNUVVZXWF'."\r\n".//50 * + 'laMTIzNDU2Nzg5MEFCQ0RFRkdISUpLTE1OT1BR'.//38 + 'UlNUVVZXWFla'; //50 * + + $this->assertEquals( + $output, $this->encoder->encodeString($input, 0, 50), + '%s: Lines should be no more than 100 characters' + ); + } + + public function testFirstLineLengthCanBeDifferent() + { + $input = + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + $output = + 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQk'.//38 + 'NERUZHSElKS0xNTk9QU'."\r\n".//57 * + 'VJTVFVWV1hZWjEyMzQ1Njc4OTBhYmNkZWZnaGl'.//38 + 'qa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLT'."\r\n".//76 * + 'E1OT1BRUlNUVVZXWFlaMTIzNDU2Nzg5MEFCQ0R'.//38 + 'FRkdISUpLTE1OT1BRUlNUVVZXWFla'; //67 + + $this->assertEquals( + $output, $this->encoder->encodeString($input, 19), + '%s: First line offset is 19 so first line should be 57 chars long' + ); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Encoder/QpEncoderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Encoder/QpEncoderTest.php new file mode 100644 index 00000000..4acd44b7 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Encoder/QpEncoderTest.php @@ -0,0 +1,400 @@ +createCharStream(); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($char); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array($ordinal)); + $charStream->shouldReceive('readBytes') + ->atLeast()->times(1) + ->andReturn(false); + + $encoder = new Swift_Encoder_QpEncoder($charStream); + + $this->assertIdenticalBinary($char, $encoder->encodeString($char)); + } + } + + public function testWhiteSpaceAtLineEndingIsEncoded() + { + /* -- RFC 2045, 6.7 -- + (3) (White Space) Octets with values of 9 and 32 MAY be + represented as US-ASCII TAB (HT) and SPACE characters, + respectively, but MUST NOT be so represented at the end + of an encoded line. Any TAB (HT) or SPACE characters + on an encoded line MUST thus be followed on that line + by a printable character. In particular, an "=" at the + end of an encoded line, indicating a soft line break + (see rule #5) may follow one or more TAB (HT) or SPACE + characters. It follows that an octet with decimal + value 9 or 32 appearing at the end of an encoded line + must be represented according to Rule #1. This rule is + necessary because some MTAs (Message Transport Agents, + programs which transport messages from one user to + another, or perform a portion of such transfers) are + known to pad lines of text with SPACEs, and others are + known to remove "white space" characters from the end + of a line. Therefore, when decoding a Quoted-Printable + body, any trailing white space on a line must be + deleted, as it will necessarily have been added by + intermediate transport agents. + */ + + $HT = chr(0x09); //9 + $SPACE = chr(0x20); //32 + + //HT + $string = 'a'.$HT.$HT."\r\n".'b'; + + $charStream = $this->createCharStream(); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($string); + + $charStream->shouldReceive('readBytes')->once()->andReturn(array(ord('a'))); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x09)); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x09)); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x0D)); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x0A)); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(ord('b'))); + $charStream->shouldReceive('readBytes')->once()->andReturn(false); + + $encoder = new Swift_Encoder_QpEncoder($charStream); + $this->assertEquals( + 'a'.$HT.'=09'."\r\n".'b', + $encoder->encodeString($string) + ); + + //SPACE + $string = 'a'.$SPACE.$SPACE."\r\n".'b'; + + $charStream = $this->createCharStream(); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($string); + + $charStream->shouldReceive('readBytes')->once()->andReturn(array(ord('a'))); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x20)); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x20)); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x0D)); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x0A)); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(ord('b'))); + $charStream->shouldReceive('readBytes')->once()->andReturn(false); + + $encoder = new Swift_Encoder_QpEncoder($charStream); + $this->assertEquals( + 'a'.$SPACE.'=20'."\r\n".'b', + $encoder->encodeString($string) + ); + } + + public function testCRLFIsLeftAlone() + { + /* + (4) (Line Breaks) A line break in a text body, represented + as a CRLF sequence in the text canonical form, must be + represented by a (RFC 822) line break, which is also a + CRLF sequence, in the Quoted-Printable encoding. Since + the canonical representation of media types other than + text do not generally include the representation of + line breaks as CRLF sequences, no hard line breaks + (i.e. line breaks that are intended to be meaningful + and to be displayed to the user) can occur in the + quoted-printable encoding of such types. Sequences + like "=0D", "=0A", "=0A=0D" and "=0D=0A" will routinely + appear in non-text data represented in quoted- + printable, of course. + + Note that many implementations may elect to encode the + local representation of various content types directly + rather than converting to canonical form first, + encoding, and then converting back to local + representation. In particular, this may apply to plain + text material on systems that use newline conventions + other than a CRLF terminator sequence. Such an + implementation optimization is permissible, but only + when the combined canonicalization-encoding step is + equivalent to performing the three steps separately. + */ + + $string = 'a'."\r\n".'b'."\r\n".'c'."\r\n"; + + $charStream = $this->createCharStream(); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($string); + + $charStream->shouldReceive('readBytes')->once()->andReturn(array(ord('a'))); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x0D)); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x0A)); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(ord('b'))); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x0D)); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x0A)); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(ord('c'))); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x0D)); + $charStream->shouldReceive('readBytes')->once()->andReturn(array(0x0A)); + $charStream->shouldReceive('readBytes')->once()->andReturn(false); + + $encoder = new Swift_Encoder_QpEncoder($charStream); + $this->assertEquals($string, $encoder->encodeString($string)); + } + + public function testLinesLongerThan76CharactersAreSoftBroken() + { + /* + (5) (Soft Line Breaks) The Quoted-Printable encoding + REQUIRES that encoded lines be no more than 76 + characters long. If longer lines are to be encoded + with the Quoted-Printable encoding, "soft" line breaks + must be used. An equal sign as the last character on a + encoded line indicates such a non-significant ("soft") + line break in the encoded text. + */ + + $input = str_repeat('a', 140); + + $charStream = $this->createCharStream(); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($input); + + $output = ''; + for ($i = 0; $i < 140; ++$i) { + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('a'))); + + if (75 == $i) { + $output .= "=\r\n"; + } + $output .= 'a'; + } + + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(false); + + $encoder = new Swift_Encoder_QpEncoder($charStream); + $this->assertEquals($output, $encoder->encodeString($input)); + } + + public function testMaxLineLengthCanBeSpecified() + { + $input = str_repeat('a', 100); + + $charStream = $this->createCharStream(); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($input); + + $output = ''; + for ($i = 0; $i < 100; ++$i) { + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('a'))); + + if (53 == $i) { + $output .= "=\r\n"; + } + $output .= 'a'; + } + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(false); + + $encoder = new Swift_Encoder_QpEncoder($charStream); + $this->assertEquals($output, $encoder->encodeString($input, 0, 54)); + } + + public function testBytesBelowPermittedRangeAreEncoded() + { + /* + According to Rule (1 & 2) + */ + + foreach (range(0, 32) as $ordinal) { + $char = chr($ordinal); + + $charStream = $this->createCharStream(); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($char); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array($ordinal)); + $charStream->shouldReceive('readBytes') + ->atLeast()->times(1) + ->andReturn(false); + + $encoder = new Swift_Encoder_QpEncoder($charStream); + + $this->assertEquals( + sprintf('=%02X', $ordinal), $encoder->encodeString($char) + ); + } + } + + public function testDecimalByte61IsEncoded() + { + /* + According to Rule (1 & 2) + */ + + $char = '='; + + $charStream = $this->createCharStream(); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($char); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(61)); + $charStream->shouldReceive('readBytes') + ->atLeast()->times(1) + ->andReturn(false); + + $encoder = new Swift_Encoder_QpEncoder($charStream); + + $this->assertEquals('=3D', $encoder->encodeString('=')); + } + + public function testBytesAbovePermittedRangeAreEncoded() + { + /* + According to Rule (1 & 2) + */ + + foreach (range(127, 255) as $ordinal) { + $char = chr($ordinal); + + $charStream = $this->createCharStream(); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($char); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array($ordinal)); + $charStream->shouldReceive('readBytes') + ->atLeast()->times(1) + ->andReturn(false); + + $encoder = new Swift_Encoder_QpEncoder($charStream); + + $this->assertEquals( + sprintf('=%02X', $ordinal), $encoder->encodeString($char) + ); + } + } + + public function testFirstLineLengthCanBeDifferent() + { + $input = str_repeat('a', 140); + + $charStream = $this->createCharStream(); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($input); + + $output = ''; + for ($i = 0; $i < 140; ++$i) { + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('a'))); + + if (53 == $i || 53 + 75 == $i) { + $output .= "=\r\n"; + } + $output .= 'a'; + } + + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(false); + + $encoder = new Swift_Encoder_QpEncoder($charStream); + $this->assertEquals( + $output, $encoder->encodeString($input, 22), + '%s: First line should start at offset 22 so can only have max length 54' + ); + } + + public function testTextIsPreWrapped() + { + $encoder = $this->createEncoder(); + + $input = str_repeat('a', 70)."\r\n". + str_repeat('a', 70)."\r\n". + str_repeat('a', 70); + + $this->assertEquals( + $input, $encoder->encodeString($input) + ); + } + + private function createCharStream() + { + return $this->getMockery('Swift_CharacterStream')->shouldIgnoreMissing(); + } + + private function createEncoder() + { + $factory = new Swift_CharacterReaderFactory_SimpleCharacterReaderFactory(); + $charStream = new Swift_CharacterStream_NgCharacterStream($factory, 'utf-8'); + + return new Swift_Encoder_QpEncoder($charStream); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Encoder/Rfc2231EncoderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Encoder/Rfc2231EncoderTest.php new file mode 100644 index 00000000..0ab8aa4c --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Encoder/Rfc2231EncoderTest.php @@ -0,0 +1,141 @@ +getMockery('Swift_CharacterStream'); + + $string = ''; + foreach (range(0x00, 0x7F) as $octet) { + $char = pack('C', $octet); + $string .= $char; + $charStream->shouldReceive('read') + ->once() + ->andReturn($char); + } + + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($string); + $charStream->shouldReceive('read') + ->atLeast()->times(1) + ->andReturn(false); + + $encoder = new Swift_Encoder_Rfc2231Encoder($charStream); + $encoded = $encoder->encodeString($string); + + foreach (explode("\r\n", $encoded) as $line) { + $this->assertRegExp($this->rfc2045Token, $line, + '%s: Encoder should always return a valid RFC 2045 token.'); + } + } + + public function testEncodingNonAsciiCharactersProducesValidToken() + { + $charStream = $this->getMockery('Swift_CharacterStream'); + + $string = ''; + foreach (range(0x80, 0xFF) as $octet) { + $char = pack('C', $octet); + $string .= $char; + $charStream->shouldReceive('read') + ->once() + ->andReturn($char); + } + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($string); + $charStream->shouldReceive('read') + ->atLeast()->times(1) + ->andReturn(false); + $encoder = new Swift_Encoder_Rfc2231Encoder($charStream); + + $encoded = $encoder->encodeString($string); + + foreach (explode("\r\n", $encoded) as $line) { + $this->assertRegExp($this->rfc2045Token, $line, + '%s: Encoder should always return a valid RFC 2045 token.'); + } + } + + public function testMaximumLineLengthCanBeSet() + { + $charStream = $this->getMockery('Swift_CharacterStream'); + + $string = ''; + for ($x = 0; $x < 200; ++$x) { + $char = 'a'; + $string .= $char; + $charStream->shouldReceive('read') + ->once() + ->andReturn($char); + } + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($string); + $charStream->shouldReceive('read') + ->atLeast()->times(1) + ->andReturn(false); + $encoder = new Swift_Encoder_Rfc2231Encoder($charStream); + + $encoded = $encoder->encodeString($string, 0, 75); + + $this->assertEquals( + str_repeat('a', 75)."\r\n". + str_repeat('a', 75)."\r\n". + str_repeat('a', 50), + $encoded, + '%s: Lines should be wrapped at each 75 characters' + ); + } + + public function testFirstLineCanHaveShorterLength() + { + $charStream = $this->getMockery('Swift_CharacterStream'); + + $string = ''; + for ($x = 0; $x < 200; ++$x) { + $char = 'a'; + $string .= $char; + $charStream->shouldReceive('read') + ->once() + ->andReturn($char); + } + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importString') + ->once() + ->with($string); + $charStream->shouldReceive('read') + ->atLeast()->times(1) + ->andReturn(false); + $encoder = new Swift_Encoder_Rfc2231Encoder($charStream); + $encoded = $encoder->encodeString($string, 25, 75); + + $this->assertEquals( + str_repeat('a', 50)."\r\n". + str_repeat('a', 75)."\r\n". + str_repeat('a', 75), + $encoded, + '%s: First line should be 25 bytes shorter than the others.' + ); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/CommandEventTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/CommandEventTest.php new file mode 100644 index 00000000..f254978c --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/CommandEventTest.php @@ -0,0 +1,34 @@ +createEvent($this->createTransport(), "FOO\r\n"); + $this->assertEquals("FOO\r\n", $evt->getCommand()); + } + + public function testSuccessCodesCanBeFetchedViaGetter() + { + $evt = $this->createEvent($this->createTransport(), "FOO\r\n", array(250)); + $this->assertEquals(array(250), $evt->getSuccessCodes()); + } + + public function testSourceIsBuffer() + { + $transport = $this->createTransport(); + $evt = $this->createEvent($transport, "FOO\r\n"); + $ref = $evt->getSource(); + $this->assertEquals($transport, $ref); + } + + private function createEvent(Swift_Transport $source, $command, $successCodes = array()) + { + return new Swift_Events_CommandEvent($source, $command, $successCodes); + } + + private function createTransport() + { + return $this->getMockBuilder('Swift_Transport')->getMock(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/EventObjectTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/EventObjectTest.php new file mode 100644 index 00000000..b67461fa --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/EventObjectTest.php @@ -0,0 +1,32 @@ +createEvent($source); + $ref = $evt->getSource(); + $this->assertEquals($source, $ref); + } + + public function testEventDoesNotHaveCancelledBubbleWhenNew() + { + $source = new stdClass(); + $evt = $this->createEvent($source); + $this->assertFalse($evt->bubbleCancelled()); + } + + public function testBubbleCanBeCancelledInEvent() + { + $source = new stdClass(); + $evt = $this->createEvent($source); + $evt->cancelBubble(); + $this->assertTrue($evt->bubbleCancelled()); + } + + private function createEvent($source) + { + return new Swift_Events_EventObject($source); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/ResponseEventTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/ResponseEventTest.php new file mode 100644 index 00000000..ba5c191c --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/ResponseEventTest.php @@ -0,0 +1,38 @@ +createEvent($this->createTransport(), "250 Ok\r\n", true); + $this->assertEquals("250 Ok\r\n", $evt->getResponse(), + '%s: Response should be available via getResponse()' + ); + } + + public function testResultCanBeFetchedViaGetter() + { + $evt = $this->createEvent($this->createTransport(), "250 Ok\r\n", false); + $this->assertFalse($evt->isValid(), + '%s: Result should be checkable via isValid()' + ); + } + + public function testSourceIsBuffer() + { + $transport = $this->createTransport(); + $evt = $this->createEvent($transport, "250 Ok\r\n", true); + $ref = $evt->getSource(); + $this->assertEquals($transport, $ref); + } + + private function createEvent(Swift_Transport $source, $response, $result) + { + return new Swift_Events_ResponseEvent($source, $response, $result); + } + + private function createTransport() + { + return $this->getMockBuilder('Swift_Transport')->getMock(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/SendEventTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/SendEventTest.php new file mode 100644 index 00000000..78dfca7a --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/SendEventTest.php @@ -0,0 +1,96 @@ +createMessage(); + $transport = $this->createTransport(); + + $evt = $this->createEvent($transport, $message); + + $ref = $evt->getMessage(); + $this->assertEquals($message, $ref, + '%s: Message should be returned from getMessage()' + ); + } + + public function testTransportCanBeFetchViaGetter() + { + $message = $this->createMessage(); + $transport = $this->createTransport(); + + $evt = $this->createEvent($transport, $message); + + $ref = $evt->getTransport(); + $this->assertEquals($transport, $ref, + '%s: Transport should be returned from getTransport()' + ); + } + + public function testTransportCanBeFetchViaGetSource() + { + $message = $this->createMessage(); + $transport = $this->createTransport(); + + $evt = $this->createEvent($transport, $message); + + $ref = $evt->getSource(); + $this->assertEquals($transport, $ref, + '%s: Transport should be returned from getSource()' + ); + } + + public function testResultCanBeSetAndGet() + { + $message = $this->createMessage(); + $transport = $this->createTransport(); + + $evt = $this->createEvent($transport, $message); + + $evt->setResult( + Swift_Events_SendEvent::RESULT_SUCCESS | Swift_Events_SendEvent::RESULT_TENTATIVE + ); + + $this->assertTrue((bool) ($evt->getResult() & Swift_Events_SendEvent::RESULT_SUCCESS)); + $this->assertTrue((bool) ($evt->getResult() & Swift_Events_SendEvent::RESULT_TENTATIVE)); + } + + public function testFailedRecipientsCanBeSetAndGet() + { + $message = $this->createMessage(); + $transport = $this->createTransport(); + + $evt = $this->createEvent($transport, $message); + + $evt->setFailedRecipients(array('foo@bar', 'zip@button')); + + $this->assertEquals(array('foo@bar', 'zip@button'), $evt->getFailedRecipients(), + '%s: FailedRecipients should be returned from getter' + ); + } + + public function testFailedRecipientsGetsPickedUpCorrectly() + { + $message = $this->createMessage(); + $transport = $this->createTransport(); + + $evt = $this->createEvent($transport, $message); + $this->assertEquals(array(), $evt->getFailedRecipients()); + } + + private function createEvent(Swift_Transport $source, Swift_Mime_SimpleMessage $message) + { + return new Swift_Events_SendEvent($source, $message); + } + + private function createTransport() + { + return $this->getMockBuilder('Swift_Transport')->getMock(); + } + + private function createMessage() + { + return $this->getMockBuilder('Swift_Mime_SimpleMessage')->disableOriginalConstructor()->getMock(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/SimpleEventDispatcherTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/SimpleEventDispatcherTest.php new file mode 100644 index 00000000..611a6df2 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/SimpleEventDispatcherTest.php @@ -0,0 +1,142 @@ +dispatcher = new Swift_Events_SimpleEventDispatcher(); + } + + public function testSendEventCanBeCreated() + { + $transport = $this->getMockBuilder('Swift_Transport')->getMock(); + $message = $this->getMockBuilder('Swift_Mime_SimpleMessage')->disableOriginalConstructor()->getMock(); + $evt = $this->dispatcher->createSendEvent($transport, $message); + $this->assertInstanceOf('Swift_Events_SendEvent', $evt); + $this->assertSame($message, $evt->getMessage()); + $this->assertSame($transport, $evt->getTransport()); + } + + public function testCommandEventCanBeCreated() + { + $buf = $this->getMockBuilder('Swift_Transport')->getMock(); + $evt = $this->dispatcher->createCommandEvent($buf, "FOO\r\n", array(250)); + $this->assertInstanceOf('Swift_Events_CommandEvent', $evt); + $this->assertSame($buf, $evt->getSource()); + $this->assertEquals("FOO\r\n", $evt->getCommand()); + $this->assertEquals(array(250), $evt->getSuccessCodes()); + } + + public function testResponseEventCanBeCreated() + { + $buf = $this->getMockBuilder('Swift_Transport')->getMock(); + $evt = $this->dispatcher->createResponseEvent($buf, "250 Ok\r\n", true); + $this->assertInstanceOf('Swift_Events_ResponseEvent', $evt); + $this->assertSame($buf, $evt->getSource()); + $this->assertEquals("250 Ok\r\n", $evt->getResponse()); + $this->assertTrue($evt->isValid()); + } + + public function testTransportChangeEventCanBeCreated() + { + $transport = $this->getMockBuilder('Swift_Transport')->getMock(); + $evt = $this->dispatcher->createTransportChangeEvent($transport); + $this->assertInstanceOf('Swift_Events_TransportChangeEvent', $evt); + $this->assertSame($transport, $evt->getSource()); + } + + public function testTransportExceptionEventCanBeCreated() + { + $transport = $this->getMockBuilder('Swift_Transport')->getMock(); + $ex = new Swift_TransportException(''); + $evt = $this->dispatcher->createTransportExceptionEvent($transport, $ex); + $this->assertInstanceOf('Swift_Events_TransportExceptionEvent', $evt); + $this->assertSame($transport, $evt->getSource()); + $this->assertSame($ex, $evt->getException()); + } + + public function testListenersAreNotifiedOfDispatchedEvent() + { + $transport = $this->getMockBuilder('Swift_Transport')->getMock(); + + $evt = $this->dispatcher->createTransportChangeEvent($transport); + + $listenerA = $this->getMockBuilder('Swift_Events_TransportChangeListener')->getMock(); + $listenerB = $this->getMockBuilder('Swift_Events_TransportChangeListener')->getMock(); + + $this->dispatcher->bindEventListener($listenerA); + $this->dispatcher->bindEventListener($listenerB); + + $listenerA->expects($this->once()) + ->method('transportStarted') + ->with($evt); + $listenerB->expects($this->once()) + ->method('transportStarted') + ->with($evt); + + $this->dispatcher->dispatchEvent($evt, 'transportStarted'); + } + + public function testListenersAreOnlyCalledIfImplementingCorrectInterface() + { + $transport = $this->getMockBuilder('Swift_Transport')->getMock(); + $message = $this->getMockBuilder('Swift_Mime_SimpleMessage')->disableOriginalConstructor()->getMock(); + + $evt = $this->dispatcher->createSendEvent($transport, $message); + + $targetListener = $this->getMockBuilder('Swift_Events_SendListener')->getMock(); + $otherListener = $this->getMockBuilder('DummyListener')->getMock(); + + $this->dispatcher->bindEventListener($targetListener); + $this->dispatcher->bindEventListener($otherListener); + + $targetListener->expects($this->once()) + ->method('sendPerformed') + ->with($evt); + $otherListener->expects($this->never()) + ->method('sendPerformed'); + + $this->dispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + public function testListenersCanCancelBubblingOfEvent() + { + $transport = $this->getMockBuilder('Swift_Transport')->getMock(); + $message = $this->getMockBuilder('Swift_Mime_SimpleMessage')->disableOriginalConstructor()->getMock(); + + $evt = $this->dispatcher->createSendEvent($transport, $message); + + $listenerA = $this->getMockBuilder('Swift_Events_SendListener')->getMock(); + $listenerB = $this->getMockBuilder('Swift_Events_SendListener')->getMock(); + + $this->dispatcher->bindEventListener($listenerA); + $this->dispatcher->bindEventListener($listenerB); + + $listenerA->expects($this->once()) + ->method('sendPerformed') + ->with($evt) + ->will($this->returnCallback(function ($object) { + $object->cancelBubble(true); + })); + $listenerB->expects($this->never()) + ->method('sendPerformed'); + + $this->dispatcher->dispatchEvent($evt, 'sendPerformed'); + + $this->assertTrue($evt->bubbleCancelled()); + } + + private function createDispatcher(array $map) + { + return new Swift_Events_SimpleEventDispatcher($map); + } +} + +class DummyListener implements Swift_Events_EventListener +{ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/TransportChangeEventTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/TransportChangeEventTest.php new file mode 100644 index 00000000..625b96c9 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/TransportChangeEventTest.php @@ -0,0 +1,30 @@ +createTransport(); + $evt = $this->createEvent($transport); + $ref = $evt->getTransport(); + $this->assertEquals($transport, $ref); + } + + public function testSourceIsTransport() + { + $transport = $this->createTransport(); + $evt = $this->createEvent($transport); + $ref = $evt->getSource(); + $this->assertEquals($transport, $ref); + } + + private function createEvent(Swift_Transport $source) + { + return new Swift_Events_TransportChangeEvent($source); + } + + private function createTransport() + { + return $this->getMockBuilder('Swift_Transport')->getMock(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/TransportExceptionEventTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/TransportExceptionEventTest.php new file mode 100644 index 00000000..033b0e5b --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Events/TransportExceptionEventTest.php @@ -0,0 +1,41 @@ +createException(); + $transport = $this->createTransport(); + $evt = $this->createEvent($transport, $ex); + $ref = $evt->getException(); + $this->assertEquals($ex, $ref, + '%s: Exception should be available via getException()' + ); + } + + public function testSourceIsTransport() + { + $ex = $this->createException(); + $transport = $this->createTransport(); + $evt = $this->createEvent($transport, $ex); + $ref = $evt->getSource(); + $this->assertEquals($transport, $ref, + '%s: Transport should be available via getSource()' + ); + } + + private function createEvent(Swift_Transport $transport, Swift_TransportException $ex) + { + return new Swift_Events_TransportExceptionEvent($transport, $ex); + } + + private function createTransport() + { + return $this->getMockBuilder('Swift_Transport')->getMock(); + } + + private function createException() + { + return new Swift_TransportException(''); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/KeyCache/ArrayKeyCacheTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/KeyCache/ArrayKeyCacheTest.php new file mode 100644 index 00000000..129c99e9 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/KeyCache/ArrayKeyCacheTest.php @@ -0,0 +1,240 @@ +createKeyCacheInputStream(); + $cache = $this->createCache($is); + $cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->assertEquals('test', $cache->getString($this->key1, 'foo')); + } + + public function testStringDataCanBeOverwritten() + { + $is = $this->createKeyCacheInputStream(); + $cache = $this->createCache($is); + $cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $cache->setString( + $this->key1, 'foo', 'whatever', Swift_KeyCache::MODE_WRITE + ); + + $this->assertEquals('whatever', $cache->getString($this->key1, 'foo')); + } + + public function testStringDataCanBeAppended() + { + $is = $this->createKeyCacheInputStream(); + $cache = $this->createCache($is); + $cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $cache->setString( + $this->key1, 'foo', 'ing', Swift_KeyCache::MODE_APPEND + ); + + $this->assertEquals('testing', $cache->getString($this->key1, 'foo')); + } + + public function testHasKeyReturnValue() + { + $is = $this->createKeyCacheInputStream(); + $cache = $this->createCache($is); + $cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + + $this->assertTrue($cache->hasKey($this->key1, 'foo')); + } + + public function testNsKeyIsWellPartitioned() + { + $is = $this->createKeyCacheInputStream(); + $cache = $this->createCache($is); + $cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $cache->setString( + $this->key2, 'foo', 'ing', Swift_KeyCache::MODE_WRITE + ); + + $this->assertEquals('test', $cache->getString($this->key1, 'foo')); + $this->assertEquals('ing', $cache->getString($this->key2, 'foo')); + } + + public function testItemKeyIsWellPartitioned() + { + $is = $this->createKeyCacheInputStream(); + $cache = $this->createCache($is); + $cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $cache->setString( + $this->key1, 'bar', 'ing', Swift_KeyCache::MODE_WRITE + ); + + $this->assertEquals('test', $cache->getString($this->key1, 'foo')); + $this->assertEquals('ing', $cache->getString($this->key1, 'bar')); + } + + public function testByteStreamCanBeImported() + { + $os = $this->createOutputStream(); + $os->expects($this->at(0)) + ->method('read') + ->will($this->returnValue('abc')); + $os->expects($this->at(1)) + ->method('read') + ->will($this->returnValue('def')); + $os->expects($this->at(2)) + ->method('read') + ->will($this->returnValue(false)); + + $is = $this->createKeyCacheInputStream(); + $cache = $this->createCache($is); + $cache->importFromByteStream( + $this->key1, 'foo', $os, Swift_KeyCache::MODE_WRITE + ); + $this->assertEquals('abcdef', $cache->getString($this->key1, 'foo')); + } + + public function testByteStreamCanBeAppended() + { + $os1 = $this->createOutputStream(); + $os1->expects($this->at(0)) + ->method('read') + ->will($this->returnValue('abc')); + $os1->expects($this->at(1)) + ->method('read') + ->will($this->returnValue('def')); + $os1->expects($this->at(2)) + ->method('read') + ->will($this->returnValue(false)); + + $os2 = $this->createOutputStream(); + $os2->expects($this->at(0)) + ->method('read') + ->will($this->returnValue('xyz')); + $os2->expects($this->at(1)) + ->method('read') + ->will($this->returnValue('uvw')); + $os2->expects($this->at(2)) + ->method('read') + ->will($this->returnValue(false)); + + $is = $this->createKeyCacheInputStream(true); + + $cache = $this->createCache($is); + + $cache->importFromByteStream( + $this->key1, 'foo', $os1, Swift_KeyCache::MODE_APPEND + ); + $cache->importFromByteStream( + $this->key1, 'foo', $os2, Swift_KeyCache::MODE_APPEND + ); + + $this->assertEquals('abcdefxyzuvw', $cache->getString($this->key1, 'foo')); + } + + public function testByteStreamAndStringCanBeAppended() + { + $os = $this->createOutputStream(); + $os->expects($this->at(0)) + ->method('read') + ->will($this->returnValue('abc')); + $os->expects($this->at(1)) + ->method('read') + ->will($this->returnValue('def')); + $os->expects($this->at(2)) + ->method('read') + ->will($this->returnValue(false)); + + $is = $this->createKeyCacheInputStream(true); + + $cache = $this->createCache($is); + + $cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_APPEND + ); + $cache->importFromByteStream( + $this->key1, 'foo', $os, Swift_KeyCache::MODE_APPEND + ); + $this->assertEquals('testabcdef', $cache->getString($this->key1, 'foo')); + } + + public function testDataCanBeExportedToByteStream() + { + //See acceptance test for more detail + $is = $this->createInputStream(); + $is->expects($this->atLeastOnce()) + ->method('write'); + + $kcis = $this->createKeyCacheInputStream(true); + + $cache = $this->createCache($kcis); + + $cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + + $cache->exportToByteStream($this->key1, 'foo', $is); + } + + public function testKeyCanBeCleared() + { + $is = $this->createKeyCacheInputStream(); + $cache = $this->createCache($is); + + $cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $this->assertTrue($cache->hasKey($this->key1, 'foo')); + $cache->clearKey($this->key1, 'foo'); + $this->assertFalse($cache->hasKey($this->key1, 'foo')); + } + + public function testNsKeyCanBeCleared() + { + $is = $this->createKeyCacheInputStream(); + $cache = $this->createCache($is); + + $cache->setString( + $this->key1, 'foo', 'test', Swift_KeyCache::MODE_WRITE + ); + $cache->setString( + $this->key1, 'bar', 'xyz', Swift_KeyCache::MODE_WRITE + ); + $this->assertTrue($cache->hasKey($this->key1, 'foo')); + $this->assertTrue($cache->hasKey($this->key1, 'bar')); + $cache->clearAll($this->key1); + $this->assertFalse($cache->hasKey($this->key1, 'foo')); + $this->assertFalse($cache->hasKey($this->key1, 'bar')); + } + + private function createCache($is) + { + return new Swift_KeyCache_ArrayKeyCache($is); + } + + private function createKeyCacheInputStream() + { + return $this->getMockBuilder('Swift_KeyCache_KeyCacheInputStream')->getMock(); + } + + private function createOutputStream() + { + return $this->getMockBuilder('Swift_OutputByteStream')->getMock(); + } + + private function createInputStream() + { + return $this->getMockBuilder('Swift_InputByteStream')->getMock(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/KeyCache/SimpleKeyCacheInputStreamTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/KeyCache/SimpleKeyCacheInputStreamTest.php new file mode 100644 index 00000000..4274aafd --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/KeyCache/SimpleKeyCacheInputStreamTest.php @@ -0,0 +1,73 @@ +getMockBuilder('Swift_KeyCache')->getMock(); + $cache->expects($this->at(0)) + ->method('setString') + ->with($this->nsKey, 'foo', 'a', Swift_KeyCache::MODE_APPEND); + $cache->expects($this->at(1)) + ->method('setString') + ->with($this->nsKey, 'foo', 'b', Swift_KeyCache::MODE_APPEND); + $cache->expects($this->at(2)) + ->method('setString') + ->with($this->nsKey, 'foo', 'c', Swift_KeyCache::MODE_APPEND); + + $stream = new Swift_KeyCache_SimpleKeyCacheInputStream(); + $stream->setKeyCache($cache); + $stream->setNsKey($this->nsKey); + $stream->setItemKey('foo'); + + $stream->write('a'); + $stream->write('b'); + $stream->write('c'); + } + + public function testFlushContentClearsKey() + { + $cache = $this->getMockBuilder('Swift_KeyCache')->getMock(); + $cache->expects($this->once()) + ->method('clearKey') + ->with($this->nsKey, 'foo'); + + $stream = new Swift_KeyCache_SimpleKeyCacheInputStream(); + $stream->setKeyCache($cache); + $stream->setNsKey($this->nsKey); + $stream->setItemKey('foo'); + + $stream->flushBuffers(); + } + + public function testClonedStreamStillReferencesSameCache() + { + $cache = $this->getMockBuilder('Swift_KeyCache')->getMock(); + $cache->expects($this->at(0)) + ->method('setString') + ->with($this->nsKey, 'foo', 'a', Swift_KeyCache::MODE_APPEND); + $cache->expects($this->at(1)) + ->method('setString') + ->with($this->nsKey, 'foo', 'b', Swift_KeyCache::MODE_APPEND); + $cache->expects($this->at(2)) + ->method('setString') + ->with('test', 'bar', 'x', Swift_KeyCache::MODE_APPEND); + + $stream = new Swift_KeyCache_SimpleKeyCacheInputStream(); + $stream->setKeyCache($cache); + $stream->setNsKey($this->nsKey); + $stream->setItemKey('foo'); + + $stream->write('a'); + $stream->write('b'); + + $newStream = clone $stream; + $newStream->setKeyCache($cache); + $newStream->setNsKey('test'); + $newStream->setItemKey('bar'); + + $newStream->write('x'); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mailer/ArrayRecipientIteratorTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mailer/ArrayRecipientIteratorTest.php new file mode 100644 index 00000000..4344910a --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mailer/ArrayRecipientIteratorTest.php @@ -0,0 +1,42 @@ +assertFalse($it->hasNext()); + } + + public function testHasNextReturnsTrueIfItemsLeft() + { + $it = new Swift_Mailer_ArrayRecipientIterator(array('foo@bar' => 'Foo')); + $this->assertTrue($it->hasNext()); + } + + public function testReadingToEndOfListCausesHasNextToReturnFalse() + { + $it = new Swift_Mailer_ArrayRecipientIterator(array('foo@bar' => 'Foo')); + $this->assertTrue($it->hasNext()); + $it->nextRecipient(); + $this->assertFalse($it->hasNext()); + } + + public function testReturnedValueHasPreservedKeyValuePair() + { + $it = new Swift_Mailer_ArrayRecipientIterator(array('foo@bar' => 'Foo')); + $this->assertEquals(array('foo@bar' => 'Foo'), $it->nextRecipient()); + } + + public function testIteratorMovesNextAfterEachIteration() + { + $it = new Swift_Mailer_ArrayRecipientIterator(array( + 'foo@bar' => 'Foo', + 'zip@button' => 'Zip thing', + 'test@test' => null, + )); + $this->assertEquals(array('foo@bar' => 'Foo'), $it->nextRecipient()); + $this->assertEquals(array('zip@button' => 'Zip thing'), $it->nextRecipient()); + $this->assertEquals(array('test@test' => null), $it->nextRecipient()); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/MailerTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/MailerTest.php new file mode 100644 index 00000000..b95e1b51 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/MailerTest.php @@ -0,0 +1,145 @@ +createTransport(); + $message = $this->createMessage(); + + $started = false; + $transport->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$started) { + return $started; + }); + $transport->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$started) { + $started = true; + + return; + }); + + $mailer = $this->createMailer($transport); + $mailer->send($message); + } + + public function testTransportIsOnlyStartedOnce() + { + $transport = $this->createTransport(); + $message = $this->createMessage(); + + $started = false; + $transport->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$started) { + return $started; + }); + $transport->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$started) { + $started = true; + + return; + }); + + $mailer = $this->createMailer($transport); + for ($i = 0; $i < 10; ++$i) { + $mailer->send($message); + } + } + + public function testMessageIsPassedToTransport() + { + $transport = $this->createTransport(); + $message = $this->createMessage(); + $transport->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()); + + $mailer = $this->createMailer($transport); + $mailer->send($message); + } + + public function testSendReturnsCountFromTransport() + { + $transport = $this->createTransport(); + $message = $this->createMessage(); + $transport->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturn(57); + + $mailer = $this->createMailer($transport); + $this->assertEquals(57, $mailer->send($message)); + } + + public function testFailedRecipientReferenceIsPassedToTransport() + { + $failures = array(); + + $transport = $this->createTransport(); + $message = $this->createMessage(); + $transport->shouldReceive('send') + ->once() + ->with($message, $failures) + ->andReturn(57); + + $mailer = $this->createMailer($transport); + $mailer->send($message, $failures); + } + + public function testSendRecordsRfcComplianceExceptionAsEntireSendFailure() + { + $failures = array(); + + $rfcException = new Swift_RfcComplianceException('test'); + $transport = $this->createTransport(); + $message = $this->createMessage(); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo&invalid' => 'Foo', 'bar@valid.tld' => 'Bar')); + $transport->shouldReceive('send') + ->once() + ->with($message, $failures) + ->andThrow($rfcException); + + $mailer = $this->createMailer($transport); + $this->assertEquals(0, $mailer->send($message, $failures), '%s: Should return 0'); + $this->assertEquals(array('foo&invalid', 'bar@valid.tld'), $failures, '%s: Failures should contain all addresses since the entire message failed to compile'); + } + + public function testRegisterPluginDelegatesToTransport() + { + $plugin = $this->createPlugin(); + $transport = $this->createTransport(); + $mailer = $this->createMailer($transport); + + $transport->shouldReceive('registerPlugin') + ->once() + ->with($plugin); + + $mailer->registerPlugin($plugin); + } + + private function createPlugin() + { + return $this->getMockery('Swift_Events_EventListener')->shouldIgnoreMissing(); + } + + private function createTransport() + { + return $this->getMockery('Swift_Transport')->shouldIgnoreMissing(); + } + + private function createMessage() + { + return $this->getMockery('Swift_Mime_SimpleMessage')->shouldIgnoreMissing(); + } + + private function createMailer(Swift_Transport $transport) + { + return new Swift_Mailer($transport); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/MessageTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/MessageTest.php new file mode 100644 index 00000000..3ebbd7ea --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/MessageTest.php @@ -0,0 +1,133 @@ +recursiveObjectCloningCheck($message1, $message2, $message1_clone); + // the test above will fail if the two messages are not identical + $this->addToAssertionCount(1); + } + + public function testCloningWithSigners() + { + $message1 = new Swift_Message('subj', 'body', 'ctype'); + $signer = new Swift_Signers_DKIMSigner(dirname(dirname(__DIR__)).'/_samples/dkim/dkim.test.priv', 'test.example', 'example'); + $message1->attachSigner($signer); + $message2 = new Swift_Message('subj', 'body', 'ctype'); + $signer = new Swift_Signers_DKIMSigner(dirname(dirname(__DIR__)).'/_samples/dkim/dkim.test.priv', 'test.example', 'example'); + $message2->attachSigner($signer); + $message1_clone = clone $message1; + + $this->recursiveObjectCloningCheck($message1, $message2, $message1_clone); + // the test above will fail if the two messages are not identical + $this->addToAssertionCount(1); + } + + public function testBodySwap() + { + $message1 = new Swift_Message('Test'); + $html = new Swift_MimePart('', 'text/html'); + $html->getHeaders()->addTextHeader('X-Test-Remove', 'Test-Value'); + $html->getHeaders()->addTextHeader('X-Test-Alter', 'Test-Value'); + $message1->attach($html); + $source = $message1->toString(); + $message2 = clone $message1; + $message2->setSubject('Message2'); + foreach ($message2->getChildren() as $child) { + $child->setBody('Test'); + $child->getHeaders()->removeAll('X-Test-Remove'); + $child->getHeaders()->get('X-Test-Alter')->setValue('Altered'); + } + $final = $message1->toString(); + if ($source != $final) { + $this->fail("Difference although object cloned \n [".$source."]\n[".$final."]\n"); + } + $final = $message2->toString(); + if ($final == $source) { + $this->fail('Two body matches although they should differ'."\n [".$source."]\n[".$final."]\n"); + } + $id_1 = $message1->getId(); + $id_2 = $message2->getId(); + $this->assertEquals($id_1, $id_2, 'Message Ids differ'); + $id_2 = $message2->generateId(); + $this->assertNotEquals($id_1, $id_2, 'Message Ids are the same'); + } + + protected function recursiveObjectCloningCheck($obj1, $obj2, $obj1_clone) + { + $obj1_properties = (array) $obj1; + $obj2_properties = (array) $obj2; + $obj1_clone_properties = (array) $obj1_clone; + + foreach ($obj1_properties as $property => $value) { + if (is_object($value)) { + $obj1_value = $obj1_properties[$property]; + $obj2_value = $obj2_properties[$property]; + $obj1_clone_value = $obj1_clone_properties[$property]; + + if ($obj1_value !== $obj2_value) { + // two separetely instanciated objects property not referencing same object + $this->assertFalse( + // but object's clone does - not everything copied + $obj1_value === $obj1_clone_value, + "Property `$property` cloning error: source and cloned objects property is referencing same object" + ); + } else { + // two separetely instanciated objects have same reference + $this->assertFalse( + // but object's clone doesn't - overdone making copies + $obj1_value !== $obj1_clone_value, + "Property `$property` not properly cloned: it should reference same object as cloning source (overdone copping)" + ); + } + // recurse + $this->recursiveObjectCloningCheck($obj1_value, $obj2_value, $obj1_clone_value); + } elseif (is_array($value)) { + $obj1_value = $obj1_properties[$property]; + $obj2_value = $obj2_properties[$property]; + $obj1_clone_value = $obj1_clone_properties[$property]; + + return $this->recursiveArrayCloningCheck($obj1_value, $obj2_value, $obj1_clone_value); + } + } + } + + protected function recursiveArrayCloningCheck($array1, $array2, $array1_clone) + { + foreach ($array1 as $key => $value) { + if (is_object($value)) { + $arr1_value = $array1[$key]; + $arr2_value = $array2[$key]; + $arr1_clone_value = $array1_clone[$key]; + if ($arr1_value !== $arr2_value) { + // two separetely instanciated objects property not referencing same object + $this->assertFalse( + // but object's clone does - not everything copied + $arr1_value === $arr1_clone_value, + "Key `$key` cloning error: source and cloned objects property is referencing same object" + ); + } else { + // two separetely instanciated objects have same reference + $this->assertFalse( + // but object's clone doesn't - overdone making copies + $arr1_value !== $arr1_clone_value, + "Key `$key` not properly cloned: it should reference same object as cloning source (overdone copping)" + ); + } + // recurse + $this->recursiveObjectCloningCheck($arr1_value, $arr2_value, $arr1_clone_value); + } elseif (is_array($value)) { + $arr1_value = $array1[$key]; + $arr2_value = $array2[$key]; + $arr1_clone_value = $array1_clone[$key]; + + return $this->recursiveArrayCloningCheck($arr1_value, $arr2_value, $arr1_clone_value); + } + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/AbstractMimeEntityTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/AbstractMimeEntityTest.php new file mode 100644 index 00000000..928b7364 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/AbstractMimeEntityTest.php @@ -0,0 +1,1092 @@ +createHeaderSet(); + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $this->assertSame($headers, $entity->getHeaders()); + } + + public function testContentTypeIsReturnedFromHeader() + { + $ctype = $this->createHeader('Content-Type', 'image/jpeg-test'); + $headers = $this->createHeaderSet(array('Content-Type' => $ctype)); + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $this->assertEquals('image/jpeg-test', $entity->getContentType()); + } + + public function testContentTypeIsSetInHeader() + { + $ctype = $this->createHeader('Content-Type', 'text/plain', array(), false); + $headers = $this->createHeaderSet(array('Content-Type' => $ctype)); + + $ctype->shouldReceive('setFieldBodyModel') + ->once() + ->with('image/jpeg'); + $ctype->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes() + ->with(\Mockery::not('image/jpeg')); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setContentType('image/jpeg'); + } + + public function testContentTypeHeaderIsAddedIfNoneSet() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addParameterizedHeader') + ->once() + ->with('Content-Type', 'image/jpeg'); + $headers->shouldReceive('addParameterizedHeader') + ->zeroOrMoreTimes(); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setContentType('image/jpeg'); + } + + public function testContentTypeCanBeSetViaSetBody() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addParameterizedHeader') + ->once() + ->with('Content-Type', 'text/html'); + $headers->shouldReceive('addParameterizedHeader') + ->zeroOrMoreTimes(); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setBody('foo', 'text/html'); + } + + public function testGetEncoderFromConstructor() + { + $encoder = $this->createEncoder('base64'); + $entity = $this->createEntity($this->createHeaderSet(), $encoder, + $this->createCache() + ); + $this->assertSame($encoder, $entity->getEncoder()); + } + + public function testSetAndGetEncoder() + { + $encoder = $this->createEncoder('base64'); + $headers = $this->createHeaderSet(); + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setEncoder($encoder); + $this->assertSame($encoder, $entity->getEncoder()); + } + + public function testSettingEncoderUpdatesTransferEncoding() + { + $encoder = $this->createEncoder('base64'); + $encoding = $this->createHeader( + 'Content-Transfer-Encoding', '8bit', array(), false + ); + $headers = $this->createHeaderSet(array( + 'Content-Transfer-Encoding' => $encoding, + )); + $encoding->shouldReceive('setFieldBodyModel') + ->once() + ->with('base64'); + $encoding->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes(); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setEncoder($encoder); + } + + public function testSettingEncoderAddsEncodingHeaderIfNonePresent() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addTextHeader') + ->once() + ->with('Content-Transfer-Encoding', 'something'); + $headers->shouldReceive('addTextHeader') + ->zeroOrMoreTimes(); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setEncoder($this->createEncoder('something')); + } + + public function testIdIsReturnedFromHeader() + { + /* -- RFC 2045, 7. + In constructing a high-level user agent, it may be desirable to allow + one body to make reference to another. Accordingly, bodies may be + labelled using the "Content-ID" header field, which is syntactically + identical to the "Message-ID" header field + */ + + $cid = $this->createHeader('Content-ID', 'zip@button'); + $headers = $this->createHeaderSet(array('Content-ID' => $cid)); + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $this->assertEquals('zip@button', $entity->getId()); + } + + public function testIdIsSetInHeader() + { + $cid = $this->createHeader('Content-ID', 'zip@button', array(), false); + $headers = $this->createHeaderSet(array('Content-ID' => $cid)); + + $cid->shouldReceive('setFieldBodyModel') + ->once() + ->with('foo@bar'); + $cid->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes(); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setId('foo@bar'); + } + + public function testIdIsAutoGenerated() + { + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $this->assertRegExp('/^.*?@.*?$/D', $entity->getId()); + } + + public function testGenerateIdCreatesNewId() + { + $headers = $this->createHeaderSet(); + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $id1 = $entity->generateId(); + $id2 = $entity->generateId(); + $this->assertNotEquals($id1, $id2); + } + + public function testGenerateIdSetsNewId() + { + $headers = $this->createHeaderSet(); + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $id = $entity->generateId(); + $this->assertEquals($id, $entity->getId()); + } + + public function testDescriptionIsReadFromHeader() + { + /* -- RFC 2045, 8. + The ability to associate some descriptive information with a given + body is often desirable. For example, it may be useful to mark an + "image" body as "a picture of the Space Shuttle Endeavor." Such text + may be placed in the Content-Description header field. This header + field is always optional. + */ + + $desc = $this->createHeader('Content-Description', 'something'); + $headers = $this->createHeaderSet(array('Content-Description' => $desc)); + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $this->assertEquals('something', $entity->getDescription()); + } + + public function testDescriptionIsSetInHeader() + { + $desc = $this->createHeader('Content-Description', '', array(), false); + $desc->shouldReceive('setFieldBodyModel')->once()->with('whatever'); + + $headers = $this->createHeaderSet(array('Content-Description' => $desc)); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setDescription('whatever'); + } + + public function testDescriptionHeaderIsAddedIfNotPresent() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addTextHeader') + ->once() + ->with('Content-Description', 'whatever'); + $headers->shouldReceive('addTextHeader') + ->zeroOrMoreTimes(); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setDescription('whatever'); + } + + public function testSetAndGetMaxLineLength() + { + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $entity->setMaxLineLength(60); + $this->assertEquals(60, $entity->getMaxLineLength()); + } + + public function testEncoderIsUsedForStringGeneration() + { + $encoder = $this->createEncoder('base64', false); + $encoder->expects($this->once()) + ->method('encodeString') + ->with('blah'); + + $entity = $this->createEntity($this->createHeaderSet(), + $encoder, $this->createCache() + ); + $entity->setBody('blah'); + $entity->toString(); + } + + public function testMaxLineLengthIsProvidedWhenEncoding() + { + $encoder = $this->createEncoder('base64', false); + $encoder->expects($this->once()) + ->method('encodeString') + ->with('blah', 0, 65); + + $entity = $this->createEntity($this->createHeaderSet(), + $encoder, $this->createCache() + ); + $entity->setBody('blah'); + $entity->setMaxLineLength(65); + $entity->toString(); + } + + public function testHeadersAppearInString() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('toString') + ->once() + ->andReturn( + "Content-Type: text/plain; charset=utf-8\r\n". + "X-MyHeader: foobar\r\n" + ); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $this->assertEquals( + "Content-Type: text/plain; charset=utf-8\r\n". + "X-MyHeader: foobar\r\n", + $entity->toString() + ); + } + + public function testSetAndGetBody() + { + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $entity->setBody("blah\r\nblah!"); + $this->assertEquals("blah\r\nblah!", $entity->getBody()); + } + + public function testBodyIsAppended() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('toString') + ->once() + ->andReturn("Content-Type: text/plain; charset=utf-8\r\n"); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setBody("blah\r\nblah!"); + $this->assertEquals( + "Content-Type: text/plain; charset=utf-8\r\n". + "\r\n". + "blah\r\nblah!", + $entity->toString() + ); + } + + public function testGetBodyReturnsStringFromByteStream() + { + $os = $this->createOutputStream('byte stream string'); + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $entity->setBody($os); + $this->assertEquals('byte stream string', $entity->getBody()); + } + + public function testByteStreamBodyIsAppended() + { + $headers = $this->createHeaderSet(array(), false); + $os = $this->createOutputStream('streamed'); + $headers->shouldReceive('toString') + ->once() + ->andReturn("Content-Type: text/plain; charset=utf-8\r\n"); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setBody($os); + $this->assertEquals( + "Content-Type: text/plain; charset=utf-8\r\n". + "\r\n". + 'streamed', + $entity->toString() + ); + } + + public function testBoundaryCanBeRetrieved() + { + /* -- RFC 2046, 5.1.1. + boundary := 0*69 bcharsnospace + + bchars := bcharsnospace / " " + + bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" / + "+" / "_" / "," / "-" / "." / + "/" / ":" / "=" / "?" + */ + + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $this->assertRegExp( + '/^[a-zA-Z0-9\'\(\)\+_\-,\.\/:=\?\ ]{0,69}[a-zA-Z0-9\'\(\)\+_\-,\.\/:=\?]$/D', + $entity->getBoundary() + ); + } + + public function testBoundaryNeverChanges() + { + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $firstBoundary = $entity->getBoundary(); + for ($i = 0; $i < 10; ++$i) { + $this->assertEquals($firstBoundary, $entity->getBoundary()); + } + } + + public function testBoundaryCanBeSet() + { + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $entity->setBoundary('foobar'); + $this->assertEquals('foobar', $entity->getBoundary()); + } + + public function testAddingChildrenGeneratesBoundaryInHeaders() + { + $child = $this->createChild(); + $cType = $this->createHeader('Content-Type', 'text/plain', array(), false); + $cType->shouldReceive('setParameter') + ->once() + ->with('boundary', \Mockery::any()); + $cType->shouldReceive('setParameter') + ->zeroOrMoreTimes(); + + $entity = $this->createEntity($this->createHeaderSet(array( + 'Content-Type' => $cType, + )), + $this->createEncoder(), $this->createCache() + ); + $entity->setChildren(array($child)); + } + + public function testChildrenOfLevelAttachmentAndLessCauseMultipartMixed() + { + for ($level = Swift_Mime_SimpleMimeEntity::LEVEL_MIXED; + $level > Swift_Mime_SimpleMimeEntity::LEVEL_TOP; $level /= 2) { + $child = $this->createChild($level); + $cType = $this->createHeader( + 'Content-Type', 'text/plain', array(), false + ); + $cType->shouldReceive('setFieldBodyModel') + ->once() + ->with('multipart/mixed'); + $cType->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes(); + + $entity = $this->createEntity($this->createHeaderSet(array( + 'Content-Type' => $cType, )), + $this->createEncoder(), $this->createCache() + ); + $entity->setChildren(array($child)); + } + } + + public function testChildrenOfLevelAlternativeAndLessCauseMultipartAlternative() + { + for ($level = Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE; + $level > Swift_Mime_SimpleMimeEntity::LEVEL_MIXED; $level /= 2) { + $child = $this->createChild($level); + $cType = $this->createHeader( + 'Content-Type', 'text/plain', array(), false + ); + $cType->shouldReceive('setFieldBodyModel') + ->once() + ->with('multipart/alternative'); + $cType->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes(); + + $entity = $this->createEntity($this->createHeaderSet(array( + 'Content-Type' => $cType, )), + $this->createEncoder(), $this->createCache() + ); + $entity->setChildren(array($child)); + } + } + + public function testChildrenOfLevelRelatedAndLessCauseMultipartRelated() + { + for ($level = Swift_Mime_SimpleMimeEntity::LEVEL_RELATED; + $level > Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE; $level /= 2) { + $child = $this->createChild($level); + $cType = $this->createHeader( + 'Content-Type', 'text/plain', array(), false + ); + $cType->shouldReceive('setFieldBodyModel') + ->once() + ->with('multipart/related'); + $cType->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes(); + + $entity = $this->createEntity($this->createHeaderSet(array( + 'Content-Type' => $cType, )), + $this->createEncoder(), $this->createCache() + ); + $entity->setChildren(array($child)); + } + } + + public function testHighestLevelChildDeterminesContentType() + { + $combinations = array( + array('levels' => array(Swift_Mime_SimpleMimeEntity::LEVEL_MIXED, + Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE, + Swift_Mime_SimpleMimeEntity::LEVEL_RELATED, + ), + 'type' => 'multipart/mixed', + ), + array('levels' => array(Swift_Mime_SimpleMimeEntity::LEVEL_MIXED, + Swift_Mime_SimpleMimeEntity::LEVEL_RELATED, + ), + 'type' => 'multipart/mixed', + ), + array('levels' => array(Swift_Mime_SimpleMimeEntity::LEVEL_MIXED, + Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE, + ), + 'type' => 'multipart/mixed', + ), + array('levels' => array(Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE, + Swift_Mime_SimpleMimeEntity::LEVEL_RELATED, + ), + 'type' => 'multipart/alternative', + ), + ); + + foreach ($combinations as $combination) { + $children = array(); + foreach ($combination['levels'] as $level) { + $children[] = $this->createChild($level); + } + + $cType = $this->createHeader( + 'Content-Type', 'text/plain', array(), false + ); + $cType->shouldReceive('setFieldBodyModel') + ->once() + ->with($combination['type']); + + $headerSet = $this->createHeaderSet(array('Content-Type' => $cType)); + $headerSet->shouldReceive('newInstance') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use ($headerSet) { + return $headerSet; + }); + $entity = $this->createEntity($headerSet, + $this->createEncoder(), $this->createCache() + ); + $entity->setChildren($children); + } + } + + public function testChildrenAppearNestedInString() + { + /* -- RFC 2046, 5.1.1. + (excerpt too verbose to paste here) + */ + + $headers = $this->createHeaderSet(array(), false); + + $child1 = new MimeEntityFixture(Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE, + "Content-Type: text/plain\r\n". + "\r\n". + 'foobar', 'text/plain' + ); + + $child2 = new MimeEntityFixture(Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE, + "Content-Type: text/html\r\n". + "\r\n". + 'foobar', 'text/html' + ); + + $headers->shouldReceive('toString') + ->zeroOrMoreTimes() + ->andReturn("Content-Type: multipart/alternative; boundary=\"xxx\"\r\n"); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setBoundary('xxx'); + $entity->setChildren(array($child1, $child2)); + + $this->assertEquals( + "Content-Type: multipart/alternative; boundary=\"xxx\"\r\n". + "\r\n". + "\r\n--xxx\r\n". + "Content-Type: text/plain\r\n". + "\r\n". + "foobar\r\n". + "\r\n--xxx\r\n". + "Content-Type: text/html\r\n". + "\r\n". + "foobar\r\n". + "\r\n--xxx--\r\n", + $entity->toString() + ); + } + + public function testMixingLevelsIsHierarchical() + { + $headers = $this->createHeaderSet(array(), false); + $newHeaders = $this->createHeaderSet(array(), false); + + $part = $this->createChild(Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE, + "Content-Type: text/plain\r\n". + "\r\n". + 'foobar' + ); + + $attachment = $this->createChild(Swift_Mime_SimpleMimeEntity::LEVEL_MIXED, + "Content-Type: application/octet-stream\r\n". + "\r\n". + 'data' + ); + + $headers->shouldReceive('toString') + ->zeroOrMoreTimes() + ->andReturn("Content-Type: multipart/mixed; boundary=\"xxx\"\r\n"); + $headers->shouldReceive('newInstance') + ->zeroOrMoreTimes() + ->andReturn($newHeaders); + $newHeaders->shouldReceive('toString') + ->zeroOrMoreTimes() + ->andReturn("Content-Type: multipart/alternative; boundary=\"yyy\"\r\n"); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setBoundary('xxx'); + $entity->setChildren(array($part, $attachment)); + + $this->assertRegExp( + '~^'. + "Content-Type: multipart/mixed; boundary=\"xxx\"\r\n". + "\r\n\r\n--xxx\r\n". + "Content-Type: multipart/alternative; boundary=\"yyy\"\r\n". + "\r\n\r\n--(.*?)\r\n". + "Content-Type: text/plain\r\n". + "\r\n". + 'foobar'. + "\r\n\r\n--\\1--\r\n". + "\r\n\r\n--xxx\r\n". + "Content-Type: application/octet-stream\r\n". + "\r\n". + 'data'. + "\r\n\r\n--xxx--\r\n". + '$~', + $entity->toString() + ); + } + + public function testSettingEncoderNotifiesChildren() + { + $child = $this->createChild(0, '', false); + $encoder = $this->createEncoder('base64'); + + $child->shouldReceive('encoderChanged') + ->once() + ->with($encoder); + + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $entity->setChildren(array($child)); + $entity->setEncoder($encoder); + } + + public function testReceiptOfEncoderChangeNotifiesChildren() + { + $child = $this->createChild(0, '', false); + $encoder = $this->createEncoder('base64'); + + $child->shouldReceive('encoderChanged') + ->once() + ->with($encoder); + + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $entity->setChildren(array($child)); + $entity->encoderChanged($encoder); + } + + public function testReceiptOfCharsetChangeNotifiesChildren() + { + $child = $this->createChild(0, '', false); + $child->shouldReceive('charsetChanged') + ->once() + ->with('windows-874'); + + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $entity->setChildren(array($child)); + $entity->charsetChanged('windows-874'); + } + + public function testEntityIsWrittenToByteStream() + { + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $is = $this->createInputStream(false); + $is->expects($this->atLeastOnce()) + ->method('write'); + + $entity->toByteStream($is); + } + + public function testEntityHeadersAreComittedToByteStream() + { + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $is = $this->createInputStream(false); + $is->expects($this->atLeastOnce()) + ->method('write'); + $is->expects($this->atLeastOnce()) + ->method('commit'); + + $entity->toByteStream($is); + } + + public function testOrderingTextBeforeHtml() + { + $htmlChild = new MimeEntityFixture(Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE, + "Content-Type: text/html\r\n". + "\r\n". + 'HTML PART', + 'text/html' + ); + $textChild = new MimeEntityFixture(Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE, + "Content-Type: text/plain\r\n". + "\r\n". + 'TEXT PART', + 'text/plain' + ); + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('toString') + ->zeroOrMoreTimes() + ->andReturn("Content-Type: multipart/alternative; boundary=\"xxx\"\r\n"); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setBoundary('xxx'); + $entity->setChildren(array($htmlChild, $textChild)); + + $this->assertEquals( + "Content-Type: multipart/alternative; boundary=\"xxx\"\r\n". + "\r\n\r\n--xxx\r\n". + "Content-Type: text/plain\r\n". + "\r\n". + 'TEXT PART'. + "\r\n\r\n--xxx\r\n". + "Content-Type: text/html\r\n". + "\r\n". + 'HTML PART'. + "\r\n\r\n--xxx--\r\n", + $entity->toString() + ); + } + + public function testOrderingEqualContentTypesMaintainsOriginalOrdering() + { + $firstChild = new MimeEntityFixture(Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE, + "Content-Type: text/plain\r\n". + "\r\n". + 'PART 1', + 'text/plain' + ); + $secondChild = new MimeEntityFixture(Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE, + "Content-Type: text/plain\r\n". + "\r\n". + 'PART 2', + 'text/plain' + ); + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('toString') + ->zeroOrMoreTimes() + ->andReturn("Content-Type: multipart/alternative; boundary=\"xxx\"\r\n"); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $this->createCache() + ); + $entity->setBoundary('xxx'); + $entity->setChildren(array($firstChild, $secondChild)); + + $this->assertEquals( + "Content-Type: multipart/alternative; boundary=\"xxx\"\r\n". + "\r\n\r\n--xxx\r\n". + "Content-Type: text/plain\r\n". + "\r\n". + 'PART 1'. + "\r\n\r\n--xxx\r\n". + "Content-Type: text/plain\r\n". + "\r\n". + 'PART 2'. + "\r\n\r\n--xxx--\r\n", + $entity->toString() + ); + } + + public function testUnsettingChildrenRestoresContentType() + { + $cType = $this->createHeader('Content-Type', 'text/plain', array(), false); + $child = $this->createChild(Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE); + + $cType->shouldReceive('setFieldBodyModel') + ->twice() + ->with('image/jpeg'); + $cType->shouldReceive('setFieldBodyModel') + ->once() + ->with('multipart/alternative'); + $cType->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes() + ->with(\Mockery::not('multipart/alternative', 'image/jpeg')); + + $entity = $this->createEntity($this->createHeaderSet(array( + 'Content-Type' => $cType, + )), + $this->createEncoder(), $this->createCache() + ); + + $entity->setContentType('image/jpeg'); + $entity->setChildren(array($child)); + $entity->setChildren(array()); + } + + public function testBodyIsReadFromCacheWhenUsingToStringIfPresent() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('toString') + ->zeroOrMoreTimes() + ->andReturn("Content-Type: text/plain; charset=utf-8\r\n"); + + $cache = $this->createCache(false); + $cache->shouldReceive('hasKey') + ->once() + ->with(\Mockery::any(), 'body') + ->andReturn(true); + $cache->shouldReceive('getString') + ->once() + ->with(\Mockery::any(), 'body') + ->andReturn("\r\ncache\r\ncache!"); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $cache + ); + + $entity->setBody("blah\r\nblah!"); + $this->assertEquals( + "Content-Type: text/plain; charset=utf-8\r\n". + "\r\n". + "cache\r\ncache!", + $entity->toString() + ); + } + + public function testBodyIsAddedToCacheWhenUsingToString() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('toString') + ->zeroOrMoreTimes() + ->andReturn("Content-Type: text/plain; charset=utf-8\r\n"); + + $cache = $this->createCache(false); + $cache->shouldReceive('hasKey') + ->once() + ->with(\Mockery::any(), 'body') + ->andReturn(false); + $cache->shouldReceive('setString') + ->once() + ->with(\Mockery::any(), 'body', "\r\nblah\r\nblah!", Swift_KeyCache::MODE_WRITE); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $cache + ); + + $entity->setBody("blah\r\nblah!"); + $entity->toString(); + } + + public function testBodyIsClearedFromCacheIfNewBodySet() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('toString') + ->zeroOrMoreTimes() + ->andReturn("Content-Type: text/plain; charset=utf-8\r\n"); + + $cache = $this->createCache(false); + $entity = $this->createEntity($headers, $this->createEncoder(), + $cache + ); + + $entity->setBody("blah\r\nblah!"); + $entity->toString(); + + // We set the expectation at this point because we only care what happens when calling setBody() + $cache->shouldReceive('clearKey') + ->once() + ->with(\Mockery::any(), 'body'); + + $entity->setBody("new\r\nnew!"); + } + + public function testBodyIsNotClearedFromCacheIfSameBodySet() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('toString') + ->zeroOrMoreTimes() + ->andReturn("Content-Type: text/plain; charset=utf-8\r\n"); + + $cache = $this->createCache(false); + $entity = $this->createEntity($headers, $this->createEncoder(), + $cache + ); + + $entity->setBody("blah\r\nblah!"); + $entity->toString(); + + // We set the expectation at this point because we only care what happens when calling setBody() + $cache->shouldReceive('clearKey') + ->never(); + + $entity->setBody("blah\r\nblah!"); + } + + public function testBodyIsClearedFromCacheIfNewEncoderSet() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('toString') + ->zeroOrMoreTimes() + ->andReturn("Content-Type: text/plain; charset=utf-8\r\n"); + + $cache = $this->createCache(false); + $otherEncoder = $this->createEncoder(); + $entity = $this->createEntity($headers, $this->createEncoder(), + $cache + ); + + $entity->setBody("blah\r\nblah!"); + $entity->toString(); + + // We set the expectation at this point because we only care what happens when calling setEncoder() + $cache->shouldReceive('clearKey') + ->once() + ->with(\Mockery::any(), 'body'); + + $entity->setEncoder($otherEncoder); + } + + public function testBodyIsReadFromCacheWhenUsingToByteStreamIfPresent() + { + $is = $this->createInputStream(); + $cache = $this->createCache(false); + $cache->shouldReceive('hasKey') + ->once() + ->with(\Mockery::any(), 'body') + ->andReturn(true); + $cache->shouldReceive('exportToByteStream') + ->once() + ->with(\Mockery::any(), 'body', $is); + + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $cache + ); + $entity->setBody('foo'); + + $entity->toByteStream($is); + } + + public function testBodyIsAddedToCacheWhenUsingToByteStream() + { + $is = $this->createInputStream(); + $cache = $this->createCache(false); + $cache->shouldReceive('hasKey') + ->once() + ->with(\Mockery::any(), 'body') + ->andReturn(false); + $cache->shouldReceive('getInputByteStream') + ->once() + ->with(\Mockery::any(), 'body'); + + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $cache + ); + $entity->setBody('foo'); + + $entity->toByteStream($is); + } + + public function testFluidInterface() + { + $entity = $this->createEntity($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + + $this->assertSame($entity, + $entity + ->setContentType('text/plain') + ->setEncoder($this->createEncoder()) + ->setId('foo@bar') + ->setDescription('my description') + ->setMaxLineLength(998) + ->setBody('xx') + ->setBoundary('xyz') + ->setChildren(array()) + ); + } + + abstract protected function createEntity($headers, $encoder, $cache); + + protected function createChild($level = null, $string = '', $stub = true) + { + $child = $this->getMockery('Swift_Mime_SimpleMimeEntity')->shouldIgnoreMissing(); + if (isset($level)) { + $child->shouldReceive('getNestingLevel') + ->zeroOrMoreTimes() + ->andReturn($level); + } + $child->shouldReceive('toString') + ->zeroOrMoreTimes() + ->andReturn($string); + + return $child; + } + + protected function createEncoder($name = 'quoted-printable', $stub = true) + { + $encoder = $this->getMockBuilder('Swift_Mime_ContentEncoder')->getMock(); + $encoder->expects($this->any()) + ->method('getName') + ->will($this->returnValue($name)); + $encoder->expects($this->any()) + ->method('encodeString') + ->will($this->returnCallback(function () { + $args = func_get_args(); + + return array_shift($args); + })); + + return $encoder; + } + + protected function createCache($stub = true) + { + return $this->getMockery('Swift_KeyCache')->shouldIgnoreMissing(); + } + + protected function createHeaderSet($headers = array(), $stub = true) + { + $set = $this->getMockery('Swift_Mime_SimpleHeaderSet')->shouldIgnoreMissing(); + $set->shouldReceive('get') + ->zeroOrMoreTimes() + ->andReturnUsing(function ($key) use ($headers) { + return $headers[$key]; + }); + $set->shouldReceive('has') + ->zeroOrMoreTimes() + ->andReturnUsing(function ($key) use ($headers) { + return array_key_exists($key, $headers); + }); + + return $set; + } + + protected function createHeader($name, $model = null, $params = array(), $stub = true) + { + $header = $this->getMockery('Swift_Mime_Headers_ParameterizedHeader')->shouldIgnoreMissing(); + $header->shouldReceive('getFieldName') + ->zeroOrMoreTimes() + ->andReturn($name); + $header->shouldReceive('getFieldBodyModel') + ->zeroOrMoreTimes() + ->andReturn($model); + $header->shouldReceive('getParameter') + ->zeroOrMoreTimes() + ->andReturnUsing(function ($key) use ($params) { + return $params[$key]; + }); + + return $header; + } + + protected function createOutputStream($data = null, $stub = true) + { + $os = $this->getMockery('Swift_OutputByteStream'); + if (isset($data)) { + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use ($data) { + static $first = true; + if (!$first) { + return false; + } + + $first = false; + + return $data; + }); + $os->shouldReceive('setReadPointer') + ->zeroOrMoreTimes(); + } + + return $os; + } + + protected function createInputStream($stub = true) + { + return $this->getMockBuilder('Swift_InputByteStream')->getMock(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/AttachmentTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/AttachmentTest.php new file mode 100644 index 00000000..adce0109 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/AttachmentTest.php @@ -0,0 +1,321 @@ +createAttachment($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals( + Swift_Mime_SimpleMimeEntity::LEVEL_MIXED, $attachment->getNestingLevel() + ); + } + + public function testDispositionIsReturnedFromHeader() + { + /* -- RFC 2183, 2.1, 2.2. + */ + + $disposition = $this->createHeader('Content-Disposition', 'attachment'); + $attachment = $this->createAttachment($this->createHeaderSet(array( + 'Content-Disposition' => $disposition, )), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals('attachment', $attachment->getDisposition()); + } + + public function testDispositionIsSetInHeader() + { + $disposition = $this->createHeader('Content-Disposition', 'attachment', + array(), false + ); + $disposition->shouldReceive('setFieldBodyModel') + ->once() + ->with('inline'); + $disposition->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes(); + + $attachment = $this->createAttachment($this->createHeaderSet(array( + 'Content-Disposition' => $disposition, )), + $this->createEncoder(), $this->createCache() + ); + $attachment->setDisposition('inline'); + } + + public function testDispositionIsAddedIfNonePresent() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addParameterizedHeader') + ->once() + ->with('Content-Disposition', 'inline'); + $headers->shouldReceive('addParameterizedHeader') + ->zeroOrMoreTimes(); + + $attachment = $this->createAttachment($headers, $this->createEncoder(), + $this->createCache() + ); + $attachment->setDisposition('inline'); + } + + public function testDispositionIsAutoDefaultedToAttachment() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addParameterizedHeader') + ->once() + ->with('Content-Disposition', 'attachment'); + $headers->shouldReceive('addParameterizedHeader') + ->zeroOrMoreTimes(); + + $attachment = $this->createAttachment($headers, $this->createEncoder(), + $this->createCache() + ); + } + + public function testDefaultContentTypeInitializedToOctetStream() + { + $cType = $this->createHeader('Content-Type', '', + array(), false + ); + $cType->shouldReceive('setFieldBodyModel') + ->once() + ->with('application/octet-stream'); + $cType->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes(); + + $attachment = $this->createAttachment($this->createHeaderSet(array( + 'Content-Type' => $cType, )), + $this->createEncoder(), $this->createCache() + ); + } + + public function testFilenameIsReturnedFromHeader() + { + /* -- RFC 2183, 2.3. + */ + + $disposition = $this->createHeader('Content-Disposition', 'attachment', + array('filename' => 'foo.txt') + ); + $attachment = $this->createAttachment($this->createHeaderSet(array( + 'Content-Disposition' => $disposition, )), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals('foo.txt', $attachment->getFilename()); + } + + public function testFilenameIsSetInHeader() + { + $disposition = $this->createHeader('Content-Disposition', 'attachment', + array('filename' => 'foo.txt'), false + ); + $disposition->shouldReceive('setParameter') + ->once() + ->with('filename', 'bar.txt'); + $disposition->shouldReceive('setParameter') + ->zeroOrMoreTimes(); + + $attachment = $this->createAttachment($this->createHeaderSet(array( + 'Content-Disposition' => $disposition, )), + $this->createEncoder(), $this->createCache() + ); + $attachment->setFilename('bar.txt'); + } + + public function testSettingFilenameSetsNameInContentType() + { + /* + This is a legacy requirement which isn't covered by up-to-date RFCs. + */ + + $cType = $this->createHeader('Content-Type', 'text/plain', + array(), false + ); + $cType->shouldReceive('setParameter') + ->once() + ->with('name', 'bar.txt'); + $cType->shouldReceive('setParameter') + ->zeroOrMoreTimes(); + + $attachment = $this->createAttachment($this->createHeaderSet(array( + 'Content-Type' => $cType, )), + $this->createEncoder(), $this->createCache() + ); + $attachment->setFilename('bar.txt'); + } + + public function testSizeIsReturnedFromHeader() + { + /* -- RFC 2183, 2.7. + */ + + $disposition = $this->createHeader('Content-Disposition', 'attachment', + array('size' => 1234) + ); + $attachment = $this->createAttachment($this->createHeaderSet(array( + 'Content-Disposition' => $disposition, )), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals(1234, $attachment->getSize()); + } + + public function testSizeIsSetInHeader() + { + $disposition = $this->createHeader('Content-Disposition', 'attachment', + array(), false + ); + $disposition->shouldReceive('setParameter') + ->once() + ->with('size', 12345); + $disposition->shouldReceive('setParameter') + ->zeroOrMoreTimes(); + + $attachment = $this->createAttachment($this->createHeaderSet(array( + 'Content-Disposition' => $disposition, )), + $this->createEncoder(), $this->createCache() + ); + $attachment->setSize(12345); + } + + public function testFilnameCanBeReadFromFileStream() + { + $file = $this->createFileStream('/bar/file.ext', ''); + $disposition = $this->createHeader('Content-Disposition', 'attachment', + array('filename' => 'foo.txt'), false + ); + $disposition->shouldReceive('setParameter') + ->once() + ->with('filename', 'file.ext'); + + $attachment = $this->createAttachment($this->createHeaderSet(array( + 'Content-Disposition' => $disposition, )), + $this->createEncoder(), $this->createCache() + ); + $attachment->setFile($file); + } + + public function testContentTypeCanBeSetViaSetFile() + { + $file = $this->createFileStream('/bar/file.ext', ''); + $disposition = $this->createHeader('Content-Disposition', 'attachment', + array('filename' => 'foo.txt'), false + ); + $disposition->shouldReceive('setParameter') + ->once() + ->with('filename', 'file.ext'); + + $ctype = $this->createHeader('Content-Type', 'text/plain', array(), false); + $ctype->shouldReceive('setFieldBodyModel') + ->once() + ->with('text/html'); + $ctype->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes(); + + $headers = $this->createHeaderSet(array( + 'Content-Disposition' => $disposition, + 'Content-Type' => $ctype, + )); + + $attachment = $this->createAttachment($headers, $this->createEncoder(), + $this->createCache() + ); + $attachment->setFile($file, 'text/html'); + } + + public function XtestContentTypeCanBeLookedUpFromCommonListIfNotProvided() + { + $file = $this->createFileStream('/bar/file.zip', ''); + $disposition = $this->createHeader('Content-Disposition', 'attachment', + array('filename' => 'foo.zip'), false + ); + $disposition->shouldReceive('setParameter') + ->once() + ->with('filename', 'file.zip'); + + $ctype = $this->createHeader('Content-Type', 'text/plain', array(), false); + $ctype->shouldReceive('setFieldBodyModel') + ->once() + ->with('application/zip'); + $ctype->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes(); + + $headers = $this->createHeaderSet(array( + 'Content-Disposition' => $disposition, + 'Content-Type' => $ctype, + )); + + $attachment = $this->createAttachment($headers, $this->createEncoder(), + $this->createCache(), array('zip' => 'application/zip', 'txt' => 'text/plain') + ); + $attachment->setFile($file); + } + + public function testDataCanBeReadFromFile() + { + $file = $this->createFileStream('/foo/file.ext', ''); + $attachment = $this->createAttachment($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $attachment->setFile($file); + $this->assertEquals('', $attachment->getBody()); + } + + public function testFluidInterface() + { + $attachment = $this->createAttachment($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $this->assertSame($attachment, + $attachment + ->setContentType('application/pdf') + ->setEncoder($this->createEncoder()) + ->setId('foo@bar') + ->setDescription('my pdf') + ->setMaxLineLength(998) + ->setBody('xx') + ->setBoundary('xyz') + ->setChildren(array()) + ->setDisposition('inline') + ->setFilename('afile.txt') + ->setSize(123) + ->setFile($this->createFileStream('foo.txt', '')) + ); + } + + protected function createEntity($headers, $encoder, $cache) + { + return $this->createAttachment($headers, $encoder, $cache); + } + + protected function createAttachment($headers, $encoder, $cache, $mimeTypes = array()) + { + $idGenerator = new Swift_Mime_IdGenerator('example.com'); + + return new Swift_Mime_Attachment($headers, $encoder, $cache, $idGenerator, $mimeTypes); + } + + protected function createFileStream($path, $data, $stub = true) + { + $file = $this->getMockery('Swift_FileStream'); + $file->shouldReceive('getPath') + ->zeroOrMoreTimes() + ->andReturn($path); + $file->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use ($data) { + static $first = true; + if (!$first) { + return false; + } + + $first = false; + + return $data; + }); + $file->shouldReceive('setReadPointer') + ->zeroOrMoreTimes(); + + return $file; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/ContentEncoder/Base64ContentEncoderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/ContentEncoder/Base64ContentEncoderTest.php new file mode 100644 index 00000000..a05c68a4 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/ContentEncoder/Base64ContentEncoderTest.php @@ -0,0 +1,323 @@ +encoder = new Swift_Mime_ContentEncoder_Base64ContentEncoder(); + } + + public function testNameIsBase64() + { + $this->assertEquals('base64', $this->encoder->getName()); + } + + /* + There's really no point in testing the entire base64 encoding to the + level QP encoding has been tested. base64_encode() has been in PHP for + years. + */ + + public function testInputOutputRatioIs3to4Bytes() + { + /* + RFC 2045, 6.8 + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + */ + + $os = $this->createOutputByteStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $os->shouldReceive('read') + ->once() + ->andReturn('123'); + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturn(false); + + $this->encoder->encodeByteStream($os, $is); + $this->assertEquals('MTIz', $collection->content); + } + + public function testPadLength() + { + /* + RFC 2045, 6.8 + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a body. When fewer than 24 input bits + are available in an input group, zero bits are added (on the right) + to form an integral number of 6-bit groups. Padding at the end of + the data is performed using the "=" character. Since all base64 + input is an integral number of octets, only the following cases can + arise: (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded output will be + an integral multiple of 4 characters with no "=" padding, (2) the + final quantum of encoding input is exactly 8 bits; here, the final + unit of encoded output will be two characters followed by two "=" + padding characters, or (3) the final quantum of encoding input is + exactly 16 bits; here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + + for ($i = 0; $i < 30; ++$i) { + $os = $this->createOutputByteStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $os->shouldReceive('read') + ->once() + ->andReturn(pack('C', random_int(0, 255))); + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturn(false); + + $this->encoder->encodeByteStream($os, $is); + $this->assertRegExp('~^[a-zA-Z0-9/\+]{2}==$~', $collection->content, + '%s: A single byte should have 2 bytes of padding' + ); + } + + for ($i = 0; $i < 30; ++$i) { + $os = $this->createOutputByteStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $os->shouldReceive('read') + ->once() + ->andReturn(pack('C*', random_int(0, 255), random_int(0, 255))); + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturn(false); + + $this->encoder->encodeByteStream($os, $is); + $this->assertRegExp('~^[a-zA-Z0-9/\+]{3}=$~', $collection->content, + '%s: Two bytes should have 1 byte of padding' + ); + } + + for ($i = 0; $i < 30; ++$i) { + $os = $this->createOutputByteStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $os->shouldReceive('read') + ->once() + ->andReturn(pack('C*', random_int(0, 255), random_int(0, 255), random_int(0, 255))); + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturn(false); + + $this->encoder->encodeByteStream($os, $is); + $this->assertRegExp('~^[a-zA-Z0-9/\+]{4}$~', $collection->content, + '%s: Three bytes should have no padding' + ); + } + } + + public function testMaximumLineLengthIs76Characters() + { + /* + The encoded output stream must be represented in lines of no more + than 76 characters each. All line breaks or other characters not + found in Table 1 must be ignored by decoding software. + */ + + $os = $this->createOutputByteStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $os->shouldReceive('read') + ->once() + ->andReturn('abcdefghijkl'); //12 + $os->shouldReceive('read') + ->once() + ->andReturn('mnopqrstuvwx'); //24 + $os->shouldReceive('read') + ->once() + ->andReturn('yzabc1234567'); //36 + $os->shouldReceive('read') + ->once() + ->andReturn('890ABCDEFGHI'); //48 + $os->shouldReceive('read') + ->once() + ->andReturn('JKLMNOPQRSTU'); //60 + $os->shouldReceive('read') + ->once() + ->andReturn('VWXYZ1234567'); //72 + $os->shouldReceive('read') + ->once() + ->andReturn('abcdefghijkl'); //84 + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturn(false); + + $this->encoder->encodeByteStream($os, $is); + $this->assertEquals( + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmMxMjM0NTY3ODkwQUJDREVGR0hJSktMTU5PUFFS\r\n". + 'U1RVVldYWVoxMjM0NTY3YWJjZGVmZ2hpamts', + $collection->content + ); + } + + public function testMaximumLineLengthCanBeDifferent() + { + $os = $this->createOutputByteStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $os->shouldReceive('read') + ->once() + ->andReturn('abcdefghijkl'); //12 + $os->shouldReceive('read') + ->once() + ->andReturn('mnopqrstuvwx'); //24 + $os->shouldReceive('read') + ->once() + ->andReturn('yzabc1234567'); //36 + $os->shouldReceive('read') + ->once() + ->andReturn('890ABCDEFGHI'); //48 + $os->shouldReceive('read') + ->once() + ->andReturn('JKLMNOPQRSTU'); //60 + $os->shouldReceive('read') + ->once() + ->andReturn('VWXYZ1234567'); //72 + $os->shouldReceive('read') + ->once() + ->andReturn('abcdefghijkl'); //84 + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturn(false); + + $this->encoder->encodeByteStream($os, $is, 0, 50); + $this->assertEquals( + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmMxMjM0NTY3OD\r\n". + "kwQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVoxMjM0NTY3YWJj\r\n". + 'ZGVmZ2hpamts', + $collection->content + ); + } + + public function testMaximumLineLengthIsNeverMoreThan76Chars() + { + $os = $this->createOutputByteStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $os->shouldReceive('read') + ->once() + ->andReturn('abcdefghijkl'); //12 + $os->shouldReceive('read') + ->once() + ->andReturn('mnopqrstuvwx'); //24 + $os->shouldReceive('read') + ->once() + ->andReturn('yzabc1234567'); //36 + $os->shouldReceive('read') + ->once() + ->andReturn('890ABCDEFGHI'); //48 + $os->shouldReceive('read') + ->once() + ->andReturn('JKLMNOPQRSTU'); //60 + $os->shouldReceive('read') + ->once() + ->andReturn('VWXYZ1234567'); //72 + $os->shouldReceive('read') + ->once() + ->andReturn('abcdefghijkl'); //84 + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturn(false); + + $this->encoder->encodeByteStream($os, $is, 0, 100); + $this->assertEquals( + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmMxMjM0NTY3ODkwQUJDREVGR0hJSktMTU5PUFFS\r\n". + 'U1RVVldYWVoxMjM0NTY3YWJjZGVmZ2hpamts', + $collection->content + ); + } + + public function testFirstLineLengthCanBeDifferent() + { + $os = $this->createOutputByteStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $os->shouldReceive('read') + ->once() + ->andReturn('abcdefghijkl'); //12 + $os->shouldReceive('read') + ->once() + ->andReturn('mnopqrstuvwx'); //24 + $os->shouldReceive('read') + ->once() + ->andReturn('yzabc1234567'); //36 + $os->shouldReceive('read') + ->once() + ->andReturn('890ABCDEFGHI'); //48 + $os->shouldReceive('read') + ->once() + ->andReturn('JKLMNOPQRSTU'); //60 + $os->shouldReceive('read') + ->once() + ->andReturn('VWXYZ1234567'); //72 + $os->shouldReceive('read') + ->once() + ->andReturn('abcdefghijkl'); //84 + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturn(false); + + $this->encoder->encodeByteStream($os, $is, 19); + $this->assertEquals( + "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXphYmMxMjM0NTY3ODkwQUJDR\r\n". + 'EVGR0hJSktMTU5PUFFSU1RVVldYWVoxMjM0NTY3YWJjZGVmZ2hpamts', + $collection->content + ); + } + + private function createOutputByteStream($stub = false) + { + return $this->getMockery('Swift_OutputByteStream')->shouldIgnoreMissing(); + } + + private function createInputByteStream($stub = false) + { + return $this->getMockery('Swift_InputByteStream')->shouldIgnoreMissing(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/ContentEncoder/PlainContentEncoderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/ContentEncoder/PlainContentEncoderTest.php new file mode 100644 index 00000000..7c673abd --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/ContentEncoder/PlainContentEncoderTest.php @@ -0,0 +1,171 @@ +getEncoder('7bit'); + $this->assertEquals('7bit', $encoder->getName()); + + $encoder = $this->getEncoder('8bit'); + $this->assertEquals('8bit', $encoder->getName()); + } + + public function testNoOctetsAreModifiedInString() + { + $encoder = $this->getEncoder('7bit'); + foreach (range(0x00, 0xFF) as $octet) { + $byte = pack('C', $octet); + $this->assertIdenticalBinary($byte, $encoder->encodeString($byte)); + } + } + + public function testNoOctetsAreModifiedInByteStream() + { + $encoder = $this->getEncoder('7bit'); + foreach (range(0x00, 0xFF) as $octet) { + $byte = pack('C', $octet); + + $os = $this->createOutputByteStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $os->shouldReceive('read') + ->once() + ->andReturn($byte); + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder->encodeByteStream($os, $is); + $this->assertIdenticalBinary($byte, $collection->content); + } + } + + public function testLineLengthCanBeSpecified() + { + $encoder = $this->getEncoder('7bit'); + + $chars = array(); + for ($i = 0; $i < 50; ++$i) { + $chars[] = 'a'; + } + $input = implode(' ', $chars); //99 chars long + + $this->assertEquals( + 'a a a a a a a a a a a a a a a a a a a a a a a a a '."\r\n".//50 * + 'a a a a a a a a a a a a a a a a a a a a a a a a a', //99 + $encoder->encodeString($input, 0, 50), + '%s: Lines should be wrapped at 50 chars' + ); + } + + public function testLineLengthCanBeSpecifiedInByteStream() + { + $encoder = $this->getEncoder('7bit'); + + $os = $this->createOutputByteStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + + for ($i = 0; $i < 50; ++$i) { + $os->shouldReceive('read') + ->once() + ->andReturn('a '); + } + + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder->encodeByteStream($os, $is, 0, 50); + $this->assertEquals( + str_repeat('a ', 25)."\r\n".str_repeat('a ', 25), + $collection->content + ); + } + + public function testencodeStringGeneratesCorrectCrlf() + { + $encoder = $this->getEncoder('7bit', true); + $this->assertEquals("a\r\nb", $encoder->encodeString("a\rb"), + '%s: Line endings should be standardized' + ); + $this->assertEquals("a\r\nb", $encoder->encodeString("a\nb"), + '%s: Line endings should be standardized' + ); + $this->assertEquals("a\r\n\r\nb", $encoder->encodeString("a\n\rb"), + '%s: Line endings should be standardized' + ); + $this->assertEquals("a\r\n\r\nb", $encoder->encodeString("a\r\rb"), + '%s: Line endings should be standardized' + ); + $this->assertEquals("a\r\n\r\nb", $encoder->encodeString("a\n\nb"), + '%s: Line endings should be standardized' + ); + } + + public function crlfProvider() + { + return array( + array("\r", "a\r\nb"), + array("\n", "a\r\nb"), + array("\n\r", "a\r\n\r\nb"), + array("\n\n", "a\r\n\r\nb"), + array("\r\r", "a\r\n\r\nb"), + ); + } + + /** + * @dataProvider crlfProvider + */ + public function testCanonicEncodeByteStreamGeneratesCorrectCrlf($test, $expected) + { + $encoder = $this->getEncoder('7bit', true); + + $os = $this->createOutputByteStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $os->shouldReceive('read') + ->once() + ->andReturn('a'); + $os->shouldReceive('read') + ->once() + ->andReturn($test); + $os->shouldReceive('read') + ->once() + ->andReturn('b'); + $os->shouldReceive('read') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder->encodeByteStream($os, $is); + $this->assertEquals($expected, $collection->content); + } + + private function getEncoder($name, $canonical = false) + { + return new Swift_Mime_ContentEncoder_PlainContentEncoder($name, $canonical); + } + + private function createOutputByteStream($stub = false) + { + return $this->getMockery('Swift_OutputByteStream')->shouldIgnoreMissing(); + } + + private function createInputByteStream($stub = false) + { + return $this->getMockery('Swift_InputByteStream')->shouldIgnoreMissing(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/ContentEncoder/QpContentEncoderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/ContentEncoder/QpContentEncoderTest.php new file mode 100644 index 00000000..d9a9abc7 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/ContentEncoder/QpContentEncoderTest.php @@ -0,0 +1,516 @@ +createCharacterStream(true) + ); + $this->assertEquals('quoted-printable', $encoder->getName()); + } + + /* -- RFC 2045, 6.7 -- + (1) (General 8bit representation) Any octet, except a CR or + LF that is part of a CRLF line break of the canonical + (standard) form of the data being encoded, may be + represented by an "=" followed by a two digit + hexadecimal representation of the octet's value. The + digits of the hexadecimal alphabet, for this purpose, + are "0123456789ABCDEF". Uppercase letters must be + used; lowercase letters are not allowed. Thus, for + example, the decimal value 12 (US-ASCII form feed) can + be represented by "=0C", and the decimal value 61 (US- + ASCII EQUAL SIGN) can be represented by "=3D". This + rule must be followed except when the following rules + allow an alternative encoding. + */ + + public function testPermittedCharactersAreNotEncoded() + { + /* -- RFC 2045, 6.7 -- + (2) (Literal representation) Octets with decimal values of + 33 through 60 inclusive, and 62 through 126, inclusive, + MAY be represented as the US-ASCII characters which + correspond to those octets (EXCLAMATION POINT through + LESS THAN, and GREATER THAN through TILDE, + respectively). + */ + + foreach (array_merge(range(33, 60), range(62, 126)) as $ordinal) { + $char = chr($ordinal); + + $os = $this->createOutputByteStream(true); + $charStream = $this->createCharacterStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importByteStream') + ->once() + ->with($os); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array($ordinal)); + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = new Swift_Mime_ContentEncoder_QpContentEncoder($charStream); + $encoder->encodeByteStream($os, $is); + $this->assertIdenticalBinary($char, $collection->content); + } + } + + public function testLinearWhiteSpaceAtLineEndingIsEncoded() + { + /* -- RFC 2045, 6.7 -- + (3) (White Space) Octets with values of 9 and 32 MAY be + represented as US-ASCII TAB (HT) and SPACE characters, + respectively, but MUST NOT be so represented at the end + of an encoded line. Any TAB (HT) or SPACE characters + on an encoded line MUST thus be followed on that line + by a printable character. In particular, an "=" at the + end of an encoded line, indicating a soft line break + (see rule #5) may follow one or more TAB (HT) or SPACE + characters. It follows that an octet with decimal + value 9 or 32 appearing at the end of an encoded line + must be represented according to Rule #1. This rule is + necessary because some MTAs (Message Transport Agents, + programs which transport messages from one user to + another, or perform a portion of such transfers) are + known to pad lines of text with SPACEs, and others are + known to remove "white space" characters from the end + of a line. Therefore, when decoding a Quoted-Printable + body, any trailing white space on a line must be + deleted, as it will necessarily have been added by + intermediate transport agents. + */ + + $HT = chr(0x09); //9 + $SPACE = chr(0x20); //32 + + //HT + $os = $this->createOutputByteStream(true); + $charStream = $this->createCharacterStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importByteStream') + ->once() + ->with($os); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('a'))); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x09)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x09)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x0D)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x0A)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('b'))); + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = new Swift_Mime_ContentEncoder_QpContentEncoder($charStream); + $encoder->encodeByteStream($os, $is); + + $this->assertEquals("a\t=09\r\nb", $collection->content); + + //SPACE + $os = $this->createOutputByteStream(true); + $charStream = $this->createCharacterStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importByteStream') + ->once() + ->with($os); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('a'))); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x20)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x20)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x0D)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x0A)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('b'))); + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = new Swift_Mime_ContentEncoder_QpContentEncoder($charStream); + $encoder->encodeByteStream($os, $is); + + $this->assertEquals("a =20\r\nb", $collection->content); + } + + public function testCRLFIsLeftAlone() + { + /* + (4) (Line Breaks) A line break in a text body, represented + as a CRLF sequence in the text canonical form, must be + represented by a (RFC 822) line break, which is also a + CRLF sequence, in the Quoted-Printable encoding. Since + the canonical representation of media types other than + text do not generally include the representation of + line breaks as CRLF sequences, no hard line breaks + (i.e. line breaks that are intended to be meaningful + and to be displayed to the user) can occur in the + quoted-printable encoding of such types. Sequences + like "=0D", "=0A", "=0A=0D" and "=0D=0A" will routinely + appear in non-text data represented in quoted- + printable, of course. + + Note that many implementations may elect to encode the + local representation of various content types directly + rather than converting to canonical form first, + encoding, and then converting back to local + representation. In particular, this may apply to plain + text material on systems that use newline conventions + other than a CRLF terminator sequence. Such an + implementation optimization is permissible, but only + when the combined canonicalization-encoding step is + equivalent to performing the three steps separately. + */ + + $os = $this->createOutputByteStream(true); + $charStream = $this->createCharacterStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importByteStream') + ->once() + ->with($os); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('a'))); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x0D)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x0A)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('b'))); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x0D)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x0A)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('c'))); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x0D)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x0A)); + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = new Swift_Mime_ContentEncoder_QpContentEncoder($charStream); + $encoder->encodeByteStream($os, $is); + $this->assertEquals("a\r\nb\r\nc\r\n", $collection->content); + } + + public function testLinesLongerThan76CharactersAreSoftBroken() + { + /* + (5) (Soft Line Breaks) The Quoted-Printable encoding + REQUIRES that encoded lines be no more than 76 + characters long. If longer lines are to be encoded + with the Quoted-Printable encoding, "soft" line breaks + must be used. An equal sign as the last character on a + encoded line indicates such a non-significant ("soft") + line break in the encoded text. + */ + + $os = $this->createOutputByteStream(true); + $charStream = $this->createCharacterStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importByteStream') + ->once() + ->with($os); + + for ($seq = 0; $seq <= 140; ++$seq) { + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('a'))); + } + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = new Swift_Mime_ContentEncoder_QpContentEncoder($charStream); + $encoder->encodeByteStream($os, $is); + $this->assertEquals(str_repeat('a', 75)."=\r\n".str_repeat('a', 66), $collection->content); + } + + public function testMaxLineLengthCanBeSpecified() + { + $os = $this->createOutputByteStream(true); + $charStream = $this->createCharacterStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importByteStream') + ->once() + ->with($os); + + for ($seq = 0; $seq <= 100; ++$seq) { + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('a'))); + } + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = new Swift_Mime_ContentEncoder_QpContentEncoder($charStream); + $encoder->encodeByteStream($os, $is, 0, 54); + $this->assertEquals(str_repeat('a', 53)."=\r\n".str_repeat('a', 48), $collection->content); + } + + public function testBytesBelowPermittedRangeAreEncoded() + { + /* + According to Rule (1 & 2) + */ + + foreach (range(0, 32) as $ordinal) { + $char = chr($ordinal); + + $os = $this->createOutputByteStream(true); + $charStream = $this->createCharacterStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importByteStream') + ->once() + ->with($os); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array($ordinal)); + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = new Swift_Mime_ContentEncoder_QpContentEncoder($charStream); + $encoder->encodeByteStream($os, $is); + $this->assertEquals(sprintf('=%02X', $ordinal), $collection->content); + } + } + + public function testDecimalByte61IsEncoded() + { + /* + According to Rule (1 & 2) + */ + + $char = chr(61); + + $os = $this->createOutputByteStream(true); + $charStream = $this->createCharacterStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importByteStream') + ->once() + ->with($os); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(61)); + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = new Swift_Mime_ContentEncoder_QpContentEncoder($charStream); + $encoder->encodeByteStream($os, $is); + $this->assertEquals(sprintf('=%02X', 61), $collection->content); + } + + public function testBytesAbovePermittedRangeAreEncoded() + { + /* + According to Rule (1 & 2) + */ + + foreach (range(127, 255) as $ordinal) { + $char = chr($ordinal); + + $os = $this->createOutputByteStream(true); + $charStream = $this->createCharacterStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importByteStream') + ->once() + ->with($os); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array($ordinal)); + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = new Swift_Mime_ContentEncoder_QpContentEncoder($charStream); + $encoder->encodeByteStream($os, $is); + $this->assertEquals(sprintf('=%02X', $ordinal), $collection->content); + } + } + + public function testFirstLineLengthCanBeDifferent() + { + $os = $this->createOutputByteStream(true); + $charStream = $this->createCharacterStream(); + $is = $this->createInputByteStream(); + $collection = new Swift_StreamCollector(); + + $is->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturnUsing($collection); + $charStream->shouldReceive('flushContents') + ->once(); + $charStream->shouldReceive('importByteStream') + ->once() + ->with($os); + + for ($seq = 0; $seq <= 140; ++$seq) { + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('a'))); + } + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = new Swift_Mime_ContentEncoder_QpContentEncoder($charStream); + $encoder->encodeByteStream($os, $is, 22); + $this->assertEquals( + str_repeat('a', 53)."=\r\n".str_repeat('a', 75)."=\r\n".str_repeat('a', 13), + $collection->content + ); + } + + public function testObserverInterfaceCanChangeCharset() + { + $stream = $this->createCharacterStream(); + $stream->shouldReceive('setCharacterSet') + ->once() + ->with('windows-1252'); + + $encoder = new Swift_Mime_ContentEncoder_QpContentEncoder($stream); + $encoder->charsetChanged('windows-1252'); + } + + public function testTextIsPreWrapped() + { + $encoder = $this->createEncoder(); + + $input = str_repeat('a', 70)."\r\n". + str_repeat('a', 70)."\r\n". + str_repeat('a', 70); + + $os = new Swift_ByteStream_ArrayByteStream(); + $is = new Swift_ByteStream_ArrayByteStream(); + $is->write($input); + + $encoder->encodeByteStream($is, $os); + + $this->assertEquals( + $input, $os->read(PHP_INT_MAX) + ); + } + + private function createCharacterStream($stub = false) + { + return $this->getMockery('Swift_CharacterStream')->shouldIgnoreMissing(); + } + + private function createEncoder() + { + $factory = new Swift_CharacterReaderFactory_SimpleCharacterReaderFactory(); + $charStream = new Swift_CharacterStream_NgCharacterStream($factory, 'utf-8'); + + return new Swift_Mime_ContentEncoder_QpContentEncoder($charStream); + } + + private function createOutputByteStream($stub = false) + { + return $this->getMockery('Swift_OutputByteStream')->shouldIgnoreMissing(); + } + + private function createInputByteStream($stub = false) + { + return $this->getMockery('Swift_InputByteStream')->shouldIgnoreMissing(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/EmbeddedFileTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/EmbeddedFileTest.php new file mode 100644 index 00000000..a0656866 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/EmbeddedFileTest.php @@ -0,0 +1,59 @@ +addToAssertionCount(1); + } + + public function testNestingLevelIsEmbedded() + { + $file = $this->createEmbeddedFile($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals( + Swift_Mime_SimpleMimeEntity::LEVEL_RELATED, $file->getNestingLevel() + ); + } + + public function testIdIsAutoGenerated() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addIdHeader') + ->once() + ->with('Content-ID', '/^.*?@.*?$/D'); + + $file = $this->createEmbeddedFile($headers, $this->createEncoder(), + $this->createCache() + ); + } + + public function testDefaultDispositionIsInline() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addParameterizedHeader') + ->once() + ->with('Content-Disposition', 'inline'); + $headers->shouldReceive('addParameterizedHeader') + ->zeroOrMoreTimes(); + + $file = $this->createEmbeddedFile($headers, $this->createEncoder(), + $this->createCache() + ); + } + + protected function createAttachment($headers, $encoder, $cache, $mimeTypes = array()) + { + return $this->createEmbeddedFile($headers, $encoder, $cache, $mimeTypes); + } + + private function createEmbeddedFile($headers, $encoder, $cache) + { + $idGenerator = new Swift_Mime_IdGenerator('example.com'); + + return new Swift_Mime_EmbeddedFile($headers, $encoder, $cache, $idGenerator); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/HeaderEncoder/Base64HeaderEncoderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/HeaderEncoder/Base64HeaderEncoderTest.php new file mode 100644 index 00000000..0db54073 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/HeaderEncoder/Base64HeaderEncoderTest.php @@ -0,0 +1,13 @@ +assertEquals('B', $encoder->getName()); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/HeaderEncoder/QpHeaderEncoderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/HeaderEncoder/QpHeaderEncoderTest.php new file mode 100644 index 00000000..79a11c4f --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/HeaderEncoder/QpHeaderEncoderTest.php @@ -0,0 +1,221 @@ +createEncoder( + $this->createCharacterStream(true) + ); + $this->assertEquals('Q', $encoder->getName()); + } + + public function testSpaceAndTabNeverAppear() + { + /* -- RFC 2047, 4. + Only a subset of the printable ASCII characters may be used in + 'encoded-text'. Space and tab characters are not allowed, so that + the beginning and end of an 'encoded-word' are obvious. + */ + + $charStream = $this->createCharacterStream(); + $charStream->shouldReceive('readBytes') + ->atLeast()->times(6) + ->andReturn(array(ord('a')), array(0x20), array(0x09), array(0x20), array(ord('b')), false); + + $encoder = $this->createEncoder($charStream); + $this->assertNotRegExp('~[ \t]~', $encoder->encodeString("a \t b"), + '%s: encoded-words in headers cannot contain LWSP as per RFC 2047.' + ); + } + + public function testSpaceIsRepresentedByUnderscore() + { + /* -- RFC 2047, 4.2. + (2) The 8-bit hexadecimal value 20 (e.g., ISO-8859-1 SPACE) may be + represented as "_" (underscore, ASCII 95.). (This character may + not pass through some internetwork mail gateways, but its use + will greatly enhance readability of "Q" encoded data with mail + readers that do not support this encoding.) Note that the "_" + always represents hexadecimal 20, even if the SPACE character + occupies a different code position in the character set in use. + */ + $charStream = $this->createCharacterStream(); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('a'))); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(0x20)); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('b'))); + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = $this->createEncoder($charStream); + $this->assertEquals('a_b', $encoder->encodeString('a b'), + '%s: Spaces can be represented by more readable underscores as per RFC 2047.' + ); + } + + public function testEqualsAndQuestionAndUnderscoreAreEncoded() + { + /* -- RFC 2047, 4.2. + (3) 8-bit values which correspond to printable ASCII characters other + than "=", "?", and "_" (underscore), MAY be represented as those + characters. (But see section 5 for restrictions.) In + particular, SPACE and TAB MUST NOT be represented as themselves + within encoded words. + */ + $charStream = $this->createCharacterStream(); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('='))); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('?'))); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('_'))); + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = $this->createEncoder($charStream); + $this->assertEquals('=3D=3F=5F', $encoder->encodeString('=?_'), + '%s: Chars =, ? and _ (underscore) may not appear as per RFC 2047.' + ); + } + + public function testParensAndQuotesAreEncoded() + { + /* -- RFC 2047, 5 (2). + A "Q"-encoded 'encoded-word' which appears in a 'comment' MUST NOT + contain the characters "(", ")" or " + */ + + $charStream = $this->createCharacterStream(); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('('))); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('"'))); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord(')'))); + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = $this->createEncoder($charStream); + $this->assertEquals('=28=22=29', $encoder->encodeString('(")'), + '%s: Chars (, " (DQUOTE) and ) may not appear as per RFC 2047.' + ); + } + + public function testOnlyCharactersAllowedInPhrasesAreUsed() + { + /* -- RFC 2047, 5. + (3) As a replacement for a 'word' entity within a 'phrase', for example, + one that precedes an address in a From, To, or Cc header. The ABNF + definition for 'phrase' from RFC 822 thus becomes: + + phrase = 1*( encoded-word / word ) + + In this case the set of characters that may be used in a "Q"-encoded + 'encoded-word' is restricted to: . An 'encoded-word' that appears within a + 'phrase' MUST be separated from any adjacent 'word', 'text' or + 'special' by 'linear-white-space'. + */ + + $allowedBytes = array_merge( + range(ord('a'), ord('z')), range(ord('A'), ord('Z')), + range(ord('0'), ord('9')), + array(ord('!'), ord('*'), ord('+'), ord('-'), ord('/')) + ); + + foreach (range(0x00, 0xFF) as $byte) { + $char = pack('C', $byte); + + $charStream = $this->createCharacterStream(); + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array($byte)); + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = $this->createEncoder($charStream); + $encodedChar = $encoder->encodeString($char); + + if (in_array($byte, $allowedBytes)) { + $this->assertEquals($char, $encodedChar, + '%s: Character '.$char.' should not be encoded.' + ); + } elseif (0x20 == $byte) { + //Special case + $this->assertEquals('_', $encodedChar, + '%s: Space character should be replaced.' + ); + } else { + $this->assertEquals(sprintf('=%02X', $byte), $encodedChar, + '%s: Byte '.$byte.' should be encoded.' + ); + } + } + } + + public function testEqualsNeverAppearsAtEndOfLine() + { + /* -- RFC 2047, 5 (3). + The 'encoded-text' in an 'encoded-word' must be self-contained; + 'encoded-text' MUST NOT be continued from one 'encoded-word' to + another. This implies that the 'encoded-text' portion of a "B" + 'encoded-word' will be a multiple of 4 characters long; for a "Q" + 'encoded-word', any "=" character that appears in the 'encoded-text' + portion will be followed by two hexadecimal characters. + */ + + $input = str_repeat('a', 140); + + $charStream = $this->createCharacterStream(); + + $output = ''; + $seq = 0; + for (; $seq < 140; ++$seq) { + $charStream->shouldReceive('readBytes') + ->once() + ->andReturn(array(ord('a'))); + + if (75 == $seq) { + $output .= "\r\n"; // =\r\n + } + $output .= 'a'; + } + + $charStream->shouldReceive('readBytes') + ->zeroOrMoreTimes() + ->andReturn(false); + + $encoder = $this->createEncoder($charStream); + $this->assertEquals($output, $encoder->encodeString($input)); + } + + private function createEncoder($charStream) + { + return new Swift_Mime_HeaderEncoder_QpHeaderEncoder($charStream); + } + + private function createCharacterStream($stub = false) + { + return $this->getMockery('Swift_CharacterStream')->shouldIgnoreMissing(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/DateHeaderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/DateHeaderTest.php new file mode 100644 index 00000000..e4193061 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/DateHeaderTest.php @@ -0,0 +1,90 @@ +getHeader('Date'); + $this->assertEquals(Swift_Mime_Header::TYPE_DATE, $header->getFieldType()); + } + + public function testGetDateTime() + { + $dateTime = new DateTimeImmutable(); + $header = $this->getHeader('Date'); + $header->setDateTime($dateTime); + $this->assertSame($dateTime, $header->getDateTime()); + } + + public function testDateTimeCanBeSetBySetter() + { + $dateTime = new DateTimeImmutable(); + $header = $this->getHeader('Date'); + $header->setDateTime($dateTime); + $this->assertSame($dateTime, $header->getDateTime()); + } + + public function testDateTimeIsConvertedToImmutable() + { + $dateTime = new DateTime(); + $header = $this->getHeader('Date'); + $header->setDateTime($dateTime); + $this->assertInstanceOf('DateTimeImmutable', $header->getDateTime()); + $this->assertEquals($dateTime->getTimestamp(), $header->getDateTime()->getTimestamp()); + $this->assertEquals($dateTime->getTimezone(), $header->getDateTime()->getTimezone()); + } + + public function testDateTimeIsImmutable() + { + $dateTime = new DateTime('2000-01-01 12:00:00 Europe/Berlin'); + $header = $this->getHeader('Date'); + $header->setDateTime($dateTime); + + $dateTime->setDate(2002, 2, 2); + $this->assertEquals('Sat, 01 Jan 2000 12:00:00 +0100', $header->getDateTime()->format('r')); + $this->assertEquals('Sat, 01 Jan 2000 12:00:00 +0100', $header->getFieldBody()); + } + + public function testDateTimeIsConvertedToRfc2822Date() + { + $dateTime = new DateTimeImmutable('2000-01-01 12:00:00 Europe/Berlin'); + $header = $this->getHeader('Date'); + $header->setDateTime($dateTime); + $this->assertEquals('Sat, 01 Jan 2000 12:00:00 +0100', $header->getFieldBody()); + } + + public function testSetBodyModel() + { + $dateTime = new DateTimeImmutable(); + $header = $this->getHeader('Date'); + $header->setFieldBodyModel($dateTime); + $this->assertEquals($dateTime->format('r'), $header->getFieldBody()); + } + + public function testGetBodyModel() + { + $dateTime = new DateTimeImmutable(); + $header = $this->getHeader('Date'); + $header->setDateTime($dateTime); + $this->assertEquals($dateTime, $header->getFieldBodyModel()); + } + + public function testToString() + { + $dateTime = new DateTimeImmutable('2000-01-01 12:00:00 Europe/Berlin'); + $header = $this->getHeader('Date'); + $header->setDateTime($dateTime); + $this->assertEquals("Date: Sat, 01 Jan 2000 12:00:00 +0100\r\n", + $header->toString() + ); + } + + private function getHeader($name) + { + return new Swift_Mime_Headers_DateHeader($name); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/IdentificationHeaderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/IdentificationHeaderTest.php new file mode 100644 index 00000000..0000c2c4 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/IdentificationHeaderTest.php @@ -0,0 +1,184 @@ +getHeader('Message-ID'); + $this->assertEquals(Swift_Mime_Header::TYPE_ID, $header->getFieldType()); + } + + public function testValueMatchesMsgIdSpec() + { + /* -- RFC 2822, 3.6.4. + message-id = "Message-ID:" msg-id CRLF + + in-reply-to = "In-Reply-To:" 1*msg-id CRLF + + references = "References:" 1*msg-id CRLF + + msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS] + + id-left = dot-atom-text / no-fold-quote / obs-id-left + + id-right = dot-atom-text / no-fold-literal / obs-id-right + + no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE + + no-fold-literal = "[" *(dtext / quoted-pair) "]" + */ + + $header = $this->getHeader('Message-ID'); + $header->setId('id-left@id-right'); + $this->assertEquals('', $header->getFieldBody()); + } + + public function testIdCanBeRetrievedVerbatim() + { + $header = $this->getHeader('Message-ID'); + $header->setId('id-left@id-right'); + $this->assertEquals('id-left@id-right', $header->getId()); + } + + public function testMultipleIdsCanBeSet() + { + $header = $this->getHeader('References'); + $header->setIds(array('a@b', 'x@y')); + $this->assertEquals(array('a@b', 'x@y'), $header->getIds()); + } + + public function testSettingMultipleIdsProducesAListValue() + { + /* -- RFC 2822, 3.6.4. + The "References:" and "In-Reply-To:" field each contain one or more + unique message identifiers, optionally separated by CFWS. + + .. SNIP .. + + in-reply-to = "In-Reply-To:" 1*msg-id CRLF + + references = "References:" 1*msg-id CRLF + */ + + $header = $this->getHeader('References'); + $header->setIds(array('a@b', 'x@y')); + $this->assertEquals(' ', $header->getFieldBody()); + } + + public function testIdLeftCanBeQuoted() + { + /* -- RFC 2822, 3.6.4. + id-left = dot-atom-text / no-fold-quote / obs-id-left + */ + + $header = $this->getHeader('References'); + $header->setId('"ab"@c'); + $this->assertEquals('"ab"@c', $header->getId()); + $this->assertEquals('<"ab"@c>', $header->getFieldBody()); + } + + public function testIdLeftCanContainAnglesAsQuotedPairs() + { + /* -- RFC 2822, 3.6.4. + no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE + */ + + $header = $this->getHeader('References'); + $header->setId('"a\\<\\>b"@c'); + $this->assertEquals('"a\\<\\>b"@c', $header->getId()); + $this->assertEquals('<"a\\<\\>b"@c>', $header->getFieldBody()); + } + + public function testIdLeftCanBeDotAtom() + { + $header = $this->getHeader('References'); + $header->setId('a.b+&%$.c@d'); + $this->assertEquals('a.b+&%$.c@d', $header->getId()); + $this->assertEquals('', $header->getFieldBody()); + } + + /** + * @expectedException \Exception + * @expectedMessageException "a b c" is not valid id-left + */ + public function testInvalidIdLeftThrowsException() + { + $header = $this->getHeader('References'); + $header->setId('a b c@d'); + } + + public function testIdRightCanBeDotAtom() + { + /* -- RFC 2822, 3.6.4. + id-right = dot-atom-text / no-fold-literal / obs-id-right + */ + + $header = $this->getHeader('References'); + $header->setId('a@b.c+&%$.d'); + $this->assertEquals('a@b.c+&%$.d', $header->getId()); + $this->assertEquals('', $header->getFieldBody()); + } + + public function testIdRightCanBeLiteral() + { + /* -- RFC 2822, 3.6.4. + no-fold-literal = "[" *(dtext / quoted-pair) "]" + */ + + $header = $this->getHeader('References'); + $header->setId('a@[1.2.3.4]'); + $this->assertEquals('a@[1.2.3.4]', $header->getId()); + $this->assertEquals('', $header->getFieldBody()); + } + + /** + * @expectedException \Exception + * @expectedMessageException "b c d" is not valid id-right + */ + public function testInvalidIdRightThrowsException() + { + $header = $this->getHeader('References'); + $header->setId('a@b c d'); + } + + /** + * @expectedException \Exception + * @expectedMessageException "abc" is does not contain @ + */ + public function testMissingAtSignThrowsException() + { + /* -- RFC 2822, 3.6.4. + msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS] + */ + $header = $this->getHeader('References'); + $header->setId('abc'); + } + + public function testSetBodyModel() + { + $header = $this->getHeader('Message-ID'); + $header->setFieldBodyModel('a@b'); + $this->assertEquals(array('a@b'), $header->getIds()); + } + + public function testGetBodyModel() + { + $header = $this->getHeader('Message-ID'); + $header->setId('a@b'); + $this->assertEquals(array('a@b'), $header->getFieldBodyModel()); + } + + public function testStringValue() + { + $header = $this->getHeader('References'); + $header->setIds(array('a@b', 'x@y')); + $this->assertEquals('References: '."\r\n", $header->toString()); + } + + private function getHeader($name) + { + return new Swift_Mime_Headers_IdentificationHeader($name, new EmailValidator()); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/MailboxHeaderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/MailboxHeaderTest.php new file mode 100644 index 00000000..680bafcf --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/MailboxHeaderTest.php @@ -0,0 +1,329 @@ +getHeader('To', $this->getEncoder('Q', true)); + $this->assertEquals(Swift_Mime_Header::TYPE_MAILBOX, $header->getFieldType()); + } + + public function testMailboxIsSetForAddress() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setAddresses('chris@swiftmailer.org'); + $this->assertEquals(array('chris@swiftmailer.org'), + $header->getNameAddressStrings() + ); + } + + public function testMailboxIsRenderedForNameAddress() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array('chris@swiftmailer.org' => 'Chris Corbyn')); + $this->assertEquals( + array('Chris Corbyn '), $header->getNameAddressStrings() + ); + } + + public function testAddressCanBeReturnedForAddress() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setAddresses('chris@swiftmailer.org'); + $this->assertEquals(array('chris@swiftmailer.org'), $header->getAddresses()); + } + + public function testAddressCanBeReturnedForNameAddress() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array('chris@swiftmailer.org' => 'Chris Corbyn')); + $this->assertEquals(array('chris@swiftmailer.org'), $header->getAddresses()); + } + + public function testQuotesInNameAreQuoted() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array( + 'chris@swiftmailer.org' => 'Chris Corbyn, "DHE"', + )); + $this->assertEquals( + array('"Chris Corbyn, \"DHE\"" '), + $header->getNameAddressStrings() + ); + } + + public function testEscapeCharsInNameAreQuoted() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array( + 'chris@swiftmailer.org' => 'Chris Corbyn, \\escaped\\', + )); + $this->assertEquals( + array('"Chris Corbyn, \\\\escaped\\\\" '), + $header->getNameAddressStrings() + ); + } + + public function testGetMailboxesReturnsNameValuePairs() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array( + 'chris@swiftmailer.org' => 'Chris Corbyn, DHE', + )); + $this->assertEquals( + array('chris@swiftmailer.org' => 'Chris Corbyn, DHE'), $header->getNameAddresses() + ); + } + + public function testMultipleAddressesCanBeSetAndFetched() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setAddresses(array( + 'chris@swiftmailer.org', 'mark@swiftmailer.org', + )); + $this->assertEquals( + array('chris@swiftmailer.org', 'mark@swiftmailer.org'), + $header->getAddresses() + ); + } + + public function testMultipleAddressesAsMailboxes() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setAddresses(array( + 'chris@swiftmailer.org', 'mark@swiftmailer.org', + )); + $this->assertEquals( + array('chris@swiftmailer.org' => null, 'mark@swiftmailer.org' => null), + $header->getNameAddresses() + ); + } + + public function testMultipleAddressesAsMailboxStrings() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setAddresses(array( + 'chris@swiftmailer.org', 'mark@swiftmailer.org', + )); + $this->assertEquals( + array('chris@swiftmailer.org', 'mark@swiftmailer.org'), + $header->getNameAddressStrings() + ); + } + + public function testMultipleNamedMailboxesReturnsMultipleAddresses() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array( + 'chris@swiftmailer.org' => 'Chris Corbyn', + 'mark@swiftmailer.org' => 'Mark Corbyn', + )); + $this->assertEquals( + array('chris@swiftmailer.org', 'mark@swiftmailer.org'), + $header->getAddresses() + ); + } + + public function testMultipleNamedMailboxesReturnsMultipleMailboxes() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array( + 'chris@swiftmailer.org' => 'Chris Corbyn', + 'mark@swiftmailer.org' => 'Mark Corbyn', + )); + $this->assertEquals(array( + 'chris@swiftmailer.org' => 'Chris Corbyn', + 'mark@swiftmailer.org' => 'Mark Corbyn', + ), + $header->getNameAddresses() + ); + } + + public function testMultipleMailboxesProducesMultipleMailboxStrings() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array( + 'chris@swiftmailer.org' => 'Chris Corbyn', + 'mark@swiftmailer.org' => 'Mark Corbyn', + )); + $this->assertEquals(array( + 'Chris Corbyn ', + 'Mark Corbyn ', + ), + $header->getNameAddressStrings() + ); + } + + public function testSetAddressesOverwritesAnyMailboxes() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array( + 'chris@swiftmailer.org' => 'Chris Corbyn', + 'mark@swiftmailer.org' => 'Mark Corbyn', + )); + $this->assertEquals( + array('chris@swiftmailer.org' => 'Chris Corbyn', + 'mark@swiftmailer.org' => 'Mark Corbyn', ), + $header->getNameAddresses() + ); + $this->assertEquals( + array('chris@swiftmailer.org', 'mark@swiftmailer.org'), + $header->getAddresses() + ); + + $header->setAddresses(array('chris@swiftmailer.org', 'mark@swiftmailer.org')); + + $this->assertEquals( + array('chris@swiftmailer.org' => null, 'mark@swiftmailer.org' => null), + $header->getNameAddresses() + ); + $this->assertEquals( + array('chris@swiftmailer.org', 'mark@swiftmailer.org'), + $header->getAddresses() + ); + } + + public function testNameIsEncodedIfNonAscii() + { + $name = 'C'.pack('C', 0x8F).'rbyn'; + + $encoder = $this->getEncoder('Q'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($name, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn('C=8Frbyn'); + + $header = $this->getHeader('From', $encoder); + $header->setNameAddresses(array('chris@swiftmailer.org' => 'Chris '.$name)); + + $addresses = $header->getNameAddressStrings(); + $this->assertEquals( + 'Chris =?'.$this->charset.'?Q?C=8Frbyn?= ', + array_shift($addresses) + ); + } + + public function testEncodingLineLengthCalculations() + { + /* -- RFC 2047, 2. + An 'encoded-word' may not be more than 75 characters long, including + 'charset', 'encoding', 'encoded-text', and delimiters. + */ + + $name = 'C'.pack('C', 0x8F).'rbyn'; + + $encoder = $this->getEncoder('Q'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($name, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn('C=8Frbyn'); + + $header = $this->getHeader('From', $encoder); + $header->setNameAddresses(array('chris@swiftmailer.org' => 'Chris '.$name)); + + $header->getNameAddressStrings(); + } + + public function testGetValueReturnsMailboxStringValue() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array( + 'chris@swiftmailer.org' => 'Chris Corbyn', + )); + $this->assertEquals( + 'Chris Corbyn ', $header->getFieldBody() + ); + } + + public function testGetValueReturnsMailboxStringValueForMultipleMailboxes() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array( + 'chris@swiftmailer.org' => 'Chris Corbyn', + 'mark@swiftmailer.org' => 'Mark Corbyn', + )); + $this->assertEquals( + 'Chris Corbyn , Mark Corbyn ', + $header->getFieldBody() + ); + } + + public function testRemoveAddressesWithSingleValue() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array( + 'chris@swiftmailer.org' => 'Chris Corbyn', + 'mark@swiftmailer.org' => 'Mark Corbyn', + )); + $header->removeAddresses('chris@swiftmailer.org'); + $this->assertEquals(array('mark@swiftmailer.org'), + $header->getAddresses() + ); + } + + public function testRemoveAddressesWithList() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array( + 'chris@swiftmailer.org' => 'Chris Corbyn', + 'mark@swiftmailer.org' => 'Mark Corbyn', + )); + $header->removeAddresses( + array('chris@swiftmailer.org', 'mark@swiftmailer.org') + ); + $this->assertEquals(array(), $header->getAddresses()); + } + + public function testSetBodyModel() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setFieldBodyModel('chris@swiftmailer.org'); + $this->assertEquals(array('chris@swiftmailer.org' => null), $header->getNameAddresses()); + } + + public function testGetBodyModel() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setAddresses(array('chris@swiftmailer.org')); + $this->assertEquals(array('chris@swiftmailer.org' => null), $header->getFieldBodyModel()); + } + + public function testToString() + { + $header = $this->getHeader('From', $this->getEncoder('Q', true)); + $header->setNameAddresses(array( + 'chris@swiftmailer.org' => 'Chris Corbyn', + 'mark@swiftmailer.org' => 'Mark Corbyn', + )); + $this->assertEquals( + 'From: Chris Corbyn , '. + 'Mark Corbyn '."\r\n", + $header->toString() + ); + } + + private function getHeader($name, $encoder) + { + $header = new Swift_Mime_Headers_MailboxHeader($name, $encoder, new EmailValidator()); + $header->setCharset($this->charset); + + return $header; + } + + private function getEncoder($type, $stub = false) + { + $encoder = $this->getMockery('Swift_Mime_HeaderEncoder')->shouldIgnoreMissing(); + $encoder->shouldReceive('getName') + ->zeroOrMoreTimes() + ->andReturn($type); + + return $encoder; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/ParameterizedHeaderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/ParameterizedHeaderTest.php new file mode 100644 index 00000000..d6657af8 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/ParameterizedHeaderTest.php @@ -0,0 +1,396 @@ +getHeader('Content-Type', + $this->getHeaderEncoder('Q', true), $this->getParameterEncoder(true) + ); + $this->assertEquals(Swift_Mime_Header::TYPE_PARAMETERIZED, $header->getFieldType()); + } + + public function testValueIsReturnedVerbatim() + { + $header = $this->getHeader('Content-Type', + $this->getHeaderEncoder('Q', true), $this->getParameterEncoder(true) + ); + $header->setValue('text/plain'); + $this->assertEquals('text/plain', $header->getValue()); + } + + public function testParametersAreAppended() + { + /* -- RFC 2045, 5.1 + parameter := attribute "=" value + + attribute := token + ; Matching of attributes + ; is ALWAYS case-insensitive. + + value := token / quoted-string + + token := 1* + + tspecials := "(" / ")" / "<" / ">" / "@" / + "," / ";" / ":" / "\" / <"> + "/" / "[" / "]" / "?" / "=" + ; Must be in quoted-string, + ; to use within parameter values + */ + + $header = $this->getHeader('Content-Type', + $this->getHeaderEncoder('Q', true), $this->getParameterEncoder(true) + ); + $header->setValue('text/plain'); + $header->setParameters(array('charset' => 'utf-8')); + $this->assertEquals('text/plain; charset=utf-8', $header->getFieldBody()); + } + + public function testSpaceInParamResultsInQuotedString() + { + $header = $this->getHeader('Content-Disposition', + $this->getHeaderEncoder('Q', true), $this->getParameterEncoder(true) + ); + $header->setValue('attachment'); + $header->setParameters(array('filename' => 'my file.txt')); + $this->assertEquals('attachment; filename="my file.txt"', + $header->getFieldBody() + ); + } + + public function testLongParamsAreBrokenIntoMultipleAttributeStrings() + { + /* -- RFC 2231, 3. + The asterisk character ("*") followed + by a decimal count is employed to indicate that multiple parameters + are being used to encapsulate a single parameter value. The count + starts at 0 and increments by 1 for each subsequent section of the + parameter value. Decimal values are used and neither leading zeroes + nor gaps in the sequence are allowed. + + The original parameter value is recovered by concatenating the + various sections of the parameter, in order. For example, the + content-type field + + Content-Type: message/external-body; access-type=URL; + URL*0="ftp://"; + URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar" + + is semantically identical to + + Content-Type: message/external-body; access-type=URL; + URL="ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar" + + Note that quotes around parameter values are part of the value + syntax; they are NOT part of the value itself. Furthermore, it is + explicitly permitted to have a mixture of quoted and unquoted + continuation fields. + */ + + $value = str_repeat('a', 180); + + $encoder = $this->getParameterEncoder(); + $encoder->shouldReceive('encodeString') + ->once() + ->with($value, \Mockery::any(), 63, \Mockery::any()) + ->andReturn(str_repeat('a', 63)."\r\n". + str_repeat('a', 63)."\r\n".str_repeat('a', 54)); + + $header = $this->getHeader('Content-Disposition', + $this->getHeaderEncoder('Q', true), $encoder + ); + $header->setValue('attachment'); + $header->setParameters(array('filename' => $value)); + $header->setMaxLineLength(78); + $this->assertEquals( + 'attachment; '. + 'filename*0*=utf-8\'\''.str_repeat('a', 63).";\r\n ". + 'filename*1*='.str_repeat('a', 63).";\r\n ". + 'filename*2*='.str_repeat('a', 54), + $header->getFieldBody() + ); + } + + public function testEncodedParamDataIncludesCharsetAndLanguage() + { + /* -- RFC 2231, 4. + Asterisks ("*") are reused to provide the indicator that language and + character set information is present and encoding is being used. A + single quote ("'") is used to delimit the character set and language + information at the beginning of the parameter value. Percent signs + ("%") are used as the encoding flag, which agrees with RFC 2047. + + Specifically, an asterisk at the end of a parameter name acts as an + indicator that character set and language information may appear at + the beginning of the parameter value. A single quote is used to + separate the character set, language, and actual value information in + the parameter value string, and an percent sign is used to flag + octets encoded in hexadecimal. For example: + + Content-Type: application/x-stuff; + title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A + + Note that it is perfectly permissible to leave either the character + set or language field blank. Note also that the single quote + delimiters MUST be present even when one of the field values is + omitted. + */ + + $value = str_repeat('a', 20).pack('C', 0x8F).str_repeat('a', 10); + + $encoder = $this->getParameterEncoder(); + $encoder->shouldReceive('encodeString') + ->once() + ->with($value, 12, 62, \Mockery::any()) + ->andReturn(str_repeat('a', 20).'%8F'.str_repeat('a', 10)); + + $header = $this->getHeader('Content-Disposition', + $this->getHeaderEncoder('Q', true), $encoder + ); + $header->setValue('attachment'); + $header->setParameters(array('filename' => $value)); + $header->setMaxLineLength(78); + $header->setLanguage($this->lang); + $this->assertEquals( + 'attachment; filename*='.$this->charset."'".$this->lang."'". + str_repeat('a', 20).'%8F'.str_repeat('a', 10), + $header->getFieldBody() + ); + } + + public function testMultipleEncodedParamLinesAreFormattedCorrectly() + { + /* -- RFC 2231, 4.1. + Character set and language information may be combined with the + parameter continuation mechanism. For example: + + Content-Type: application/x-stuff + title*0*=us-ascii'en'This%20is%20even%20more%20 + title*1*=%2A%2A%2Afun%2A%2A%2A%20 + title*2="isn't it!" + + Note that: + + (1) Language and character set information only appear at + the beginning of a given parameter value. + + (2) Continuations do not provide a facility for using more + than one character set or language in the same + parameter value. + + (3) A value presented using multiple continuations may + contain a mixture of encoded and unencoded segments. + + (4) The first segment of a continuation MUST be encoded if + language and character set information are given. + + (5) If the first segment of a continued parameter value is + encoded the language and character set field delimiters + MUST be present even when the fields are left blank. + */ + + $value = str_repeat('a', 20).pack('C', 0x8F).str_repeat('a', 60); + + $encoder = $this->getParameterEncoder(); + $encoder->shouldReceive('encodeString') + ->once() + ->with($value, 12, 62, \Mockery::any()) + ->andReturn(str_repeat('a', 20).'%8F'.str_repeat('a', 28)."\r\n". + str_repeat('a', 32)); + + $header = $this->getHeader('Content-Disposition', + $this->getHeaderEncoder('Q', true), $encoder + ); + $header->setValue('attachment'); + $header->setParameters(array('filename' => $value)); + $header->setMaxLineLength(78); + $header->setLanguage($this->lang); + $this->assertEquals( + 'attachment; filename*0*='.$this->charset."'".$this->lang."'". + str_repeat('a', 20).'%8F'.str_repeat('a', 28).";\r\n ". + 'filename*1*='.str_repeat('a', 32), + $header->getFieldBody() + ); + } + + public function testToString() + { + $header = $this->getHeader('Content-Type', + $this->getHeaderEncoder('Q', true), $this->getParameterEncoder(true) + ); + $header->setValue('text/html'); + $header->setParameters(array('charset' => 'utf-8')); + $this->assertEquals('Content-Type: text/html; charset=utf-8'."\r\n", + $header->toString() + ); + } + + public function testValueCanBeEncodedIfNonAscii() + { + $value = 'fo'.pack('C', 0x8F).'bar'; + + $encoder = $this->getHeaderEncoder('Q'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($value, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn('fo=8Fbar'); + + $header = $this->getHeader('X-Foo', $encoder, $this->getParameterEncoder(true)); + $header->setValue($value); + $header->setParameters(array('lookslike' => 'foobar')); + $this->assertEquals('X-Foo: =?utf-8?Q?fo=8Fbar?=; lookslike=foobar'."\r\n", + $header->toString() + ); + } + + public function testValueAndParamCanBeEncodedIfNonAscii() + { + $value = 'fo'.pack('C', 0x8F).'bar'; + + $encoder = $this->getHeaderEncoder('Q'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($value, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn('fo=8Fbar'); + + $paramEncoder = $this->getParameterEncoder(); + $paramEncoder->shouldReceive('encodeString') + ->once() + ->with($value, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn('fo%8Fbar'); + + $header = $this->getHeader('X-Foo', $encoder, $paramEncoder); + $header->setValue($value); + $header->setParameters(array('says' => $value)); + $this->assertEquals("X-Foo: =?utf-8?Q?fo=8Fbar?=; says*=utf-8''fo%8Fbar\r\n", + $header->toString() + ); + } + + public function testParamsAreEncodedWithEncodedWordsIfNoParamEncoderSet() + { + $value = 'fo'.pack('C', 0x8F).'bar'; + + $encoder = $this->getHeaderEncoder('Q'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($value, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn('fo=8Fbar'); + + $header = $this->getHeader('X-Foo', $encoder, null); + $header->setValue('bar'); + $header->setParameters(array('says' => $value)); + $this->assertEquals("X-Foo: bar; says=\"=?utf-8?Q?fo=8Fbar?=\"\r\n", + $header->toString() + ); + } + + public function testLanguageInformationAppearsInEncodedWords() + { + /* -- RFC 2231, 5. + 5. Language specification in Encoded Words + + RFC 2047 provides support for non-US-ASCII character sets in RFC 822 + message header comments, phrases, and any unstructured text field. + This is done by defining an encoded word construct which can appear + in any of these places. Given that these are fields intended for + display, it is sometimes necessary to associate language information + with encoded words as well as just the character set. This + specification extends the definition of an encoded word to allow the + inclusion of such information. This is simply done by suffixing the + character set specification with an asterisk followed by the language + tag. For example: + + From: =?US-ASCII*EN?Q?Keith_Moore?= + */ + + $value = 'fo'.pack('C', 0x8F).'bar'; + + $encoder = $this->getHeaderEncoder('Q'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($value, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn('fo=8Fbar'); + + $paramEncoder = $this->getParameterEncoder(); + $paramEncoder->shouldReceive('encodeString') + ->once() + ->with($value, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn('fo%8Fbar'); + + $header = $this->getHeader('X-Foo', $encoder, $paramEncoder); + $header->setLanguage('en'); + $header->setValue($value); + $header->setParameters(array('says' => $value)); + $this->assertEquals("X-Foo: =?utf-8*en?Q?fo=8Fbar?=; says*=utf-8'en'fo%8Fbar\r\n", + $header->toString() + ); + } + + public function testSetBodyModel() + { + $header = $this->getHeader('Content-Type', + $this->getHeaderEncoder('Q', true), $this->getParameterEncoder(true) + ); + $header->setFieldBodyModel('text/html'); + $this->assertEquals('text/html', $header->getValue()); + } + + public function testGetBodyModel() + { + $header = $this->getHeader('Content-Type', + $this->getHeaderEncoder('Q', true), $this->getParameterEncoder(true) + ); + $header->setValue('text/plain'); + $this->assertEquals('text/plain', $header->getFieldBodyModel()); + } + + public function testSetParameter() + { + $header = $this->getHeader('Content-Type', + $this->getHeaderEncoder('Q', true), $this->getParameterEncoder(true) + ); + $header->setParameters(array('charset' => 'utf-8', 'delsp' => 'yes')); + $header->setParameter('delsp', 'no'); + $this->assertEquals(array('charset' => 'utf-8', 'delsp' => 'no'), + $header->getParameters() + ); + } + + public function testGetParameter() + { + $header = $this->getHeader('Content-Type', + $this->getHeaderEncoder('Q', true), $this->getParameterEncoder(true) + ); + $header->setParameters(array('charset' => 'utf-8', 'delsp' => 'yes')); + $this->assertEquals('utf-8', $header->getParameter('charset')); + } + + private function getHeader($name, $encoder, $paramEncoder) + { + $header = new Swift_Mime_Headers_ParameterizedHeader($name, $encoder, $paramEncoder); + $header->setCharset($this->charset); + + return $header; + } + + private function getHeaderEncoder($type, $stub = false) + { + $encoder = $this->getMockery('Swift_Mime_HeaderEncoder')->shouldIgnoreMissing(); + $encoder->shouldReceive('getName') + ->zeroOrMoreTimes() + ->andReturn($type); + + return $encoder; + } + + private function getParameterEncoder($stub = false) + { + return $this->getMockery('Swift_Encoder')->shouldIgnoreMissing(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/PathHeaderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/PathHeaderTest.php new file mode 100644 index 00000000..278678ec --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/PathHeaderTest.php @@ -0,0 +1,78 @@ +getHeader('Return-Path'); + $this->assertEquals(Swift_Mime_Header::TYPE_PATH, $header->getFieldType()); + } + + public function testSingleAddressCanBeSetAndFetched() + { + $header = $this->getHeader('Return-Path'); + $header->setAddress('chris@swiftmailer.org'); + $this->assertEquals('chris@swiftmailer.org', $header->getAddress()); + } + + /** + * @expectedException \Exception + */ + public function testAddressMustComplyWithRfc2822() + { + $header = $this->getHeader('Return-Path'); + $header->setAddress('chr is@swiftmailer.org'); + } + + public function testValueIsAngleAddrWithValidAddress() + { + /* -- RFC 2822, 3.6.7. + + return = "Return-Path:" path CRLF + + path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) / + obs-path + */ + + $header = $this->getHeader('Return-Path'); + $header->setAddress('chris@swiftmailer.org'); + $this->assertEquals('', $header->getFieldBody()); + } + + public function testValueIsEmptyAngleBracketsIfEmptyAddressSet() + { + $header = $this->getHeader('Return-Path'); + $header->setAddress(''); + $this->assertEquals('<>', $header->getFieldBody()); + } + + public function testSetBodyModel() + { + $header = $this->getHeader('Return-Path'); + $header->setFieldBodyModel('foo@bar.tld'); + $this->assertEquals('foo@bar.tld', $header->getAddress()); + } + + public function testGetBodyModel() + { + $header = $this->getHeader('Return-Path'); + $header->setAddress('foo@bar.tld'); + $this->assertEquals('foo@bar.tld', $header->getFieldBodyModel()); + } + + public function testToString() + { + $header = $this->getHeader('Return-Path'); + $header->setAddress('chris@swiftmailer.org'); + $this->assertEquals('Return-Path: '."\r\n", + $header->toString() + ); + } + + private function getHeader($name) + { + return new Swift_Mime_Headers_PathHeader($name, new EmailValidator()); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/UnstructuredHeaderTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/UnstructuredHeaderTest.php new file mode 100644 index 00000000..b3dc1a7e --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/Headers/UnstructuredHeaderTest.php @@ -0,0 +1,353 @@ +getHeader('Subject', $this->getEncoder('Q', true)); + $this->assertEquals(Swift_Mime_Header::TYPE_TEXT, $header->getFieldType()); + } + + public function testGetNameReturnsNameVerbatim() + { + $header = $this->getHeader('Subject', $this->getEncoder('Q', true)); + $this->assertEquals('Subject', $header->getFieldName()); + } + + public function testGetValueReturnsValueVerbatim() + { + $header = $this->getHeader('Subject', $this->getEncoder('Q', true)); + $header->setValue('Test'); + $this->assertEquals('Test', $header->getValue()); + } + + public function testBasicStructureIsKeyValuePair() + { + /* -- RFC 2822, 2.2 + Header fields are lines composed of a field name, followed by a colon + (":"), followed by a field body, and terminated by CRLF. + */ + $header = $this->getHeader('Subject', $this->getEncoder('Q', true)); + $header->setValue('Test'); + $this->assertEquals('Subject: Test'."\r\n", $header->toString()); + } + + public function testLongHeadersAreFoldedAtWordBoundary() + { + /* -- RFC 2822, 2.2.3 + Each header field is logically a single line of characters comprising + the field name, the colon, and the field body. For convenience + however, and to deal with the 998/78 character limitations per line, + the field body portion of a header field can be split into a multiple + line representation; this is called "folding". The general rule is + that wherever this standard allows for folding white space (not + simply WSP characters), a CRLF may be inserted before any WSP. + */ + + $value = 'The quick brown fox jumped over the fence, he was a very very '. + 'scary brown fox with a bushy tail'; + $header = $this->getHeader('X-Custom-Header', + $this->getEncoder('Q', true) + ); + $header->setValue($value); + $header->setMaxLineLength(78); //A safe [RFC 2822, 2.2.3] default + /* + X-Custom-Header: The quick brown fox jumped over the fence, he was a very very + scary brown fox with a bushy tail + */ + $this->assertEquals( + 'X-Custom-Header: The quick brown fox jumped over the fence, he was a'. + ' very very'."\r\n".//Folding + ' scary brown fox with a bushy tail'."\r\n", + $header->toString(), '%s: The header should have been folded at 78th char' + ); + } + + public function testPrintableAsciiOnlyAppearsInHeaders() + { + /* -- RFC 2822, 2.2. + A field name MUST be composed of printable US-ASCII characters (i.e., + characters that have values between 33 and 126, inclusive), except + colon. A field body may be composed of any US-ASCII characters, + except for CR and LF. + */ + + $nonAsciiChar = pack('C', 0x8F); + $header = $this->getHeader('X-Test', $this->getEncoder('Q', true)); + $header->setValue($nonAsciiChar); + $this->assertRegExp( + '~^[^:\x00-\x20\x80-\xFF]+: [^\x80-\xFF\r\n]+\r\n$~s', + $header->toString() + ); + } + + public function testEncodedWordsFollowGeneralStructure() + { + /* -- RFC 2047, 1. + Generally, an "encoded-word" is a sequence of printable ASCII + characters that begins with "=?", ends with "?=", and has two "?"s in + between. + */ + + $nonAsciiChar = pack('C', 0x8F); + $header = $this->getHeader('X-Test', $this->getEncoder('Q', true)); + $header->setValue($nonAsciiChar); + $this->assertRegExp( + '~^X-Test: \=?.*?\?.*?\?.*?\?=\r\n$~s', + $header->toString() + ); + } + + public function testEncodedWordIncludesCharsetAndEncodingMethodAndText() + { + /* -- RFC 2047, 2. + An 'encoded-word' is defined by the following ABNF grammar. The + notation of RFC 822 is used, with the exception that white space + characters MUST NOT appear between components of an 'encoded-word'. + + encoded-word = "=?" charset "?" encoding "?" encoded-text "?=" + */ + + $nonAsciiChar = pack('C', 0x8F); + + $encoder = $this->getEncoder('Q'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($nonAsciiChar, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn('=8F'); + + $header = $this->getHeader('X-Test', $encoder); + $header->setValue($nonAsciiChar); + $this->assertEquals( + 'X-Test: =?'.$this->charset.'?Q?=8F?='."\r\n", + $header->toString() + ); + } + + public function testEncodedWordsAreUsedToEncodedNonPrintableAscii() + { + //SPACE and TAB permitted + $nonPrintableBytes = array_merge( + range(0x00, 0x08), range(0x10, 0x19), array(0x7F) + ); + + foreach ($nonPrintableBytes as $byte) { + $char = pack('C', $byte); + $encodedChar = sprintf('=%02X', $byte); + + $encoder = $this->getEncoder('Q'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($char, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn($encodedChar); + + $header = $this->getHeader('X-A', $encoder); + $header->setValue($char); + + $this->assertEquals( + 'X-A: =?'.$this->charset.'?Q?'.$encodedChar.'?='."\r\n", + $header->toString(), '%s: Non-printable ascii should be encoded' + ); + } + } + + public function testEncodedWordsAreUsedToEncode8BitOctets() + { + foreach (range(0x80, 0xFF) as $byte) { + $char = pack('C', $byte); + $encodedChar = sprintf('=%02X', $byte); + + $encoder = $this->getEncoder('Q'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($char, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn($encodedChar); + + $header = $this->getHeader('X-A', $encoder); + $header->setValue($char); + + $this->assertEquals( + 'X-A: =?'.$this->charset.'?Q?'.$encodedChar.'?='."\r\n", + $header->toString(), '%s: 8-bit octets should be encoded' + ); + } + } + + public function testEncodedWordsAreNoMoreThan75CharsPerLine() + { + /* -- RFC 2047, 2. + An 'encoded-word' may not be more than 75 characters long, including + 'charset', 'encoding', 'encoded-text', and delimiters. + + ... SNIP ... + + While there is no limit to the length of a multiple-line header + field, each line of a header field that contains one or more + 'encoded-word's is limited to 76 characters. + */ + + $nonAsciiChar = pack('C', 0x8F); + + $encoder = $this->getEncoder('Q'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($nonAsciiChar, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn('=8F'); + //Note that multi-line headers begin with LWSP which makes 75 + 1 = 76 + //Note also that =?utf-8?q??= is 12 chars which makes 75 - 12 = 63 + + //* X-Test: is 8 chars + $header = $this->getHeader('X-Test', $encoder); + $header->setValue($nonAsciiChar); + + $this->assertEquals( + 'X-Test: =?'.$this->charset.'?Q?=8F?='."\r\n", + $header->toString() + ); + } + + public function testFWSPIsUsedWhenEncoderReturnsMultipleLines() + { + /* --RFC 2047, 2. + If it is desirable to encode more text than will fit in an 'encoded-word' of + 75 characters, multiple 'encoded-word's (separated by CRLF SPACE) may + be used. + */ + + //Note the Mock does NOT return 8F encoded, the 8F merely triggers + // encoding for the sake of testing + $nonAsciiChar = pack('C', 0x8F); + + $encoder = $this->getEncoder('Q'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($nonAsciiChar, 8, 63, \Mockery::any()) + ->andReturn('line_one_here'."\r\n".'line_two_here'); + + //Note that multi-line headers begin with LWSP which makes 75 + 1 = 76 + //Note also that =?utf-8?q??= is 12 chars which makes 75 - 12 = 63 + + //* X-Test: is 8 chars + $header = $this->getHeader('X-Test', $encoder); + $header->setValue($nonAsciiChar); + + $this->assertEquals( + 'X-Test: =?'.$this->charset.'?Q?line_one_here?='."\r\n". + ' =?'.$this->charset.'?Q?line_two_here?='."\r\n", + $header->toString() + ); + } + + public function testAdjacentWordsAreEncodedTogether() + { + /* -- RFC 2047, 5 (1) + Ordinary ASCII text and 'encoded-word's may appear together in the + same header field. However, an 'encoded-word' that appears in a + header field defined as '*text' MUST be separated from any adjacent + 'encoded-word' or 'text' by 'linear-white-space'. + + -- RFC 2047, 2. + IMPORTANT: 'encoded-word's are designed to be recognized as 'atom's + by an RFC 822 parser. As a consequence, unencoded white space + characters (such as SPACE and HTAB) are FORBIDDEN within an + 'encoded-word'. + */ + + //It would be valid to encode all words needed, however it's probably + // easiest to encode the longest amount required at a time + + $word = 'w'.pack('C', 0x8F).'rd'; + $text = 'start '.$word.' '.$word.' then end '.$word; + // 'start', ' word word', ' and end', ' word' + + $encoder = $this->getEncoder('Q'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($word.' '.$word, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn('w=8Frd_w=8Frd'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($word, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn('w=8Frd'); + + $header = $this->getHeader('X-Test', $encoder); + $header->setValue($text); + + $headerString = $header->toString(); + + $this->assertEquals('X-Test: start =?'.$this->charset.'?Q?'. + 'w=8Frd_w=8Frd?= then end =?'.$this->charset.'?Q?'. + 'w=8Frd?='."\r\n", $headerString, + '%s: Adjacent encoded words should appear grouped with WSP encoded' + ); + } + + public function testLanguageInformationAppearsInEncodedWords() + { + /* -- RFC 2231, 5. + 5. Language specification in Encoded Words + + RFC 2047 provides support for non-US-ASCII character sets in RFC 822 + message header comments, phrases, and any unstructured text field. + This is done by defining an encoded word construct which can appear + in any of these places. Given that these are fields intended for + display, it is sometimes necessary to associate language information + with encoded words as well as just the character set. This + specification extends the definition of an encoded word to allow the + inclusion of such information. This is simply done by suffixing the + character set specification with an asterisk followed by the language + tag. For example: + + From: =?US-ASCII*EN?Q?Keith_Moore?= + */ + + $value = 'fo'.pack('C', 0x8F).'bar'; + + $encoder = $this->getEncoder('Q'); + $encoder->shouldReceive('encodeString') + ->once() + ->with($value, \Mockery::any(), \Mockery::any(), \Mockery::any()) + ->andReturn('fo=8Fbar'); + + $header = $this->getHeader('Subject', $encoder); + $header->setLanguage('en'); + $header->setValue($value); + $this->assertEquals("Subject: =?utf-8*en?Q?fo=8Fbar?=\r\n", + $header->toString() + ); + } + + public function testSetBodyModel() + { + $header = $this->getHeader('Subject', $this->getEncoder('Q', true)); + $header->setFieldBodyModel('test'); + $this->assertEquals('test', $header->getValue()); + } + + public function testGetBodyModel() + { + $header = $this->getHeader('Subject', $this->getEncoder('Q', true)); + $header->setValue('test'); + $this->assertEquals('test', $header->getFieldBodyModel()); + } + + private function getHeader($name, $encoder) + { + $header = new Swift_Mime_Headers_UnstructuredHeader($name, $encoder); + $header->setCharset($this->charset); + + return $header; + } + + private function getEncoder($type, $stub = false) + { + $encoder = $this->getMockery('Swift_Mime_HeaderEncoder')->shouldIgnoreMissing(); + $encoder->shouldReceive('getName') + ->zeroOrMoreTimes() + ->andReturn($type); + + return $encoder; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/IdGeneratorTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/IdGeneratorTest.php new file mode 100644 index 00000000..e0571a30 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/IdGeneratorTest.php @@ -0,0 +1,32 @@ +assertEquals('example.net', $idGenerator->getIdRight()); + + $idGenerator->setIdRight('example.com'); + $this->assertEquals('example.com', $idGenerator->getIdRight()); + } + + public function testIdGenerateId() + { + $idGenerator = new Swift_Mime_IdGenerator('example.net'); + $emailValidator = new EmailValidator(); + + $id = $idGenerator->generateId(); + $this->assertTrue($emailValidator->isValid($id, new RFCValidation())); + $this->assertEquals(1, preg_match('/^.{32}@example.net$/', $id)); + + $anotherId = $idGenerator->generateId(); + $this->assertNotEquals($id, $anotherId); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/MimePartTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/MimePartTest.php new file mode 100644 index 00000000..7bf49345 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/MimePartTest.php @@ -0,0 +1,234 @@ +createMimePart($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals( + Swift_Mime_SimpleMimeEntity::LEVEL_ALTERNATIVE, $part->getNestingLevel() + ); + } + + public function testCharsetIsReturnedFromHeader() + { + /* -- RFC 2046, 4.1.2. + A critical parameter that may be specified in the Content-Type field + for "text/plain" data is the character set. This is specified with a + "charset" parameter, as in: + + Content-type: text/plain; charset=iso-8859-1 + + Unlike some other parameter values, the values of the charset + parameter are NOT case sensitive. The default character set, which + must be assumed in the absence of a charset parameter, is US-ASCII. + */ + + $cType = $this->createHeader('Content-Type', 'text/plain', + array('charset' => 'iso-8859-1') + ); + $part = $this->createMimePart($this->createHeaderSet(array( + 'Content-Type' => $cType, )), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals('iso-8859-1', $part->getCharset()); + } + + public function testCharsetIsSetInHeader() + { + $cType = $this->createHeader('Content-Type', 'text/plain', + array('charset' => 'iso-8859-1'), false + ); + $cType->shouldReceive('setParameter')->once()->with('charset', 'utf-8'); + + $part = $this->createMimePart($this->createHeaderSet(array( + 'Content-Type' => $cType, )), + $this->createEncoder(), $this->createCache() + ); + $part->setCharset('utf-8'); + } + + public function testCharsetIsSetInHeaderIfPassedToSetBody() + { + $cType = $this->createHeader('Content-Type', 'text/plain', + array('charset' => 'iso-8859-1'), false + ); + $cType->shouldReceive('setParameter')->once()->with('charset', 'utf-8'); + + $part = $this->createMimePart($this->createHeaderSet(array( + 'Content-Type' => $cType, )), + $this->createEncoder(), $this->createCache() + ); + $part->setBody('', 'text/plian', 'utf-8'); + } + + public function testSettingCharsetNotifiesEncoder() + { + $encoder = $this->createEncoder('quoted-printable', false); + $encoder->expects($this->once()) + ->method('charsetChanged') + ->with('utf-8'); + + $part = $this->createMimePart($this->createHeaderSet(), + $encoder, $this->createCache() + ); + $part->setCharset('utf-8'); + } + + public function testSettingCharsetNotifiesHeaders() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('charsetChanged') + ->zeroOrMoreTimes() + ->with('utf-8'); + + $part = $this->createMimePart($headers, $this->createEncoder(), + $this->createCache() + ); + $part->setCharset('utf-8'); + } + + public function testSettingCharsetNotifiesChildren() + { + $child = $this->createChild(0, '', false); + $child->shouldReceive('charsetChanged') + ->once() + ->with('windows-874'); + + $part = $this->createMimePart($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $part->setChildren(array($child)); + $part->setCharset('windows-874'); + } + + public function testCharsetChangeUpdatesCharset() + { + $cType = $this->createHeader('Content-Type', 'text/plain', + array('charset' => 'iso-8859-1'), false + ); + $cType->shouldReceive('setParameter')->once()->with('charset', 'utf-8'); + + $part = $this->createMimePart($this->createHeaderSet(array( + 'Content-Type' => $cType, )), + $this->createEncoder(), $this->createCache() + ); + $part->charsetChanged('utf-8'); + } + + public function testSettingCharsetClearsCache() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('toString') + ->zeroOrMoreTimes() + ->andReturn("Content-Type: text/plain; charset=utf-8\r\n"); + + $cache = $this->createCache(false); + + $entity = $this->createEntity($headers, $this->createEncoder(), + $cache + ); + + $entity->setBody("blah\r\nblah!"); + $entity->toString(); + + // Initialize the expectation here because we only care about what happens in setCharset() + $cache->shouldReceive('clearKey') + ->once() + ->with(\Mockery::any(), 'body'); + + $entity->setCharset('iso-2022'); + } + + public function testFormatIsReturnedFromHeader() + { + /* -- RFC 3676. + */ + + $cType = $this->createHeader('Content-Type', 'text/plain', + array('format' => 'flowed') + ); + $part = $this->createMimePart($this->createHeaderSet(array( + 'Content-Type' => $cType, )), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals('flowed', $part->getFormat()); + } + + public function testFormatIsSetInHeader() + { + $cType = $this->createHeader('Content-Type', 'text/plain', array(), false); + $cType->shouldReceive('setParameter')->once()->with('format', 'fixed'); + + $part = $this->createMimePart($this->createHeaderSet(array( + 'Content-Type' => $cType, )), + $this->createEncoder(), $this->createCache() + ); + $part->setFormat('fixed'); + } + + public function testDelSpIsReturnedFromHeader() + { + /* -- RFC 3676. + */ + + $cType = $this->createHeader('Content-Type', 'text/plain', + array('delsp' => 'no') + ); + $part = $this->createMimePart($this->createHeaderSet(array( + 'Content-Type' => $cType, )), + $this->createEncoder(), $this->createCache() + ); + $this->assertFalse($part->getDelSp()); + } + + public function testDelSpIsSetInHeader() + { + $cType = $this->createHeader('Content-Type', 'text/plain', array(), false); + $cType->shouldReceive('setParameter')->once()->with('delsp', 'yes'); + + $part = $this->createMimePart($this->createHeaderSet(array( + 'Content-Type' => $cType, )), + $this->createEncoder(), $this->createCache() + ); + $part->setDelSp(true); + } + + public function testFluidInterface() + { + $part = $this->createMimePart($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + + $this->assertSame($part, + $part + ->setContentType('text/plain') + ->setEncoder($this->createEncoder()) + ->setId('foo@bar') + ->setDescription('my description') + ->setMaxLineLength(998) + ->setBody('xx') + ->setBoundary('xyz') + ->setChildren(array()) + ->setCharset('utf-8') + ->setFormat('flowed') + ->setDelSp(true) + ); + } + + //abstract + protected function createEntity($headers, $encoder, $cache) + { + return $this->createMimePart($headers, $encoder, $cache); + } + + protected function createMimePart($headers, $encoder, $cache) + { + $idGenerator = new Swift_Mime_IdGenerator('example.com'); + + return new Swift_Mime_MimePart($headers, $encoder, $cache, $idGenerator); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleHeaderFactoryTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleHeaderFactoryTest.php new file mode 100644 index 00000000..5a16ad16 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleHeaderFactoryTest.php @@ -0,0 +1,169 @@ +factory = $this->createFactory(); + } + + public function testMailboxHeaderIsCorrectType() + { + $header = $this->factory->createMailboxHeader('X-Foo'); + $this->assertInstanceOf('Swift_Mime_Headers_MailboxHeader', $header); + } + + public function testMailboxHeaderHasCorrectName() + { + $header = $this->factory->createMailboxHeader('X-Foo'); + $this->assertEquals('X-Foo', $header->getFieldName()); + } + + public function testMailboxHeaderHasCorrectModel() + { + $header = $this->factory->createMailboxHeader('X-Foo', + array('foo@bar' => 'FooBar') + ); + $this->assertEquals(array('foo@bar' => 'FooBar'), $header->getFieldBodyModel()); + } + + public function testDateHeaderHasCorrectType() + { + $header = $this->factory->createDateHeader('X-Date'); + $this->assertInstanceOf('Swift_Mime_Headers_DateHeader', $header); + } + + public function testDateHeaderHasCorrectName() + { + $header = $this->factory->createDateHeader('X-Date'); + $this->assertEquals('X-Date', $header->getFieldName()); + } + + public function testDateHeaderHasCorrectModel() + { + $dateTime = new \DateTimeImmutable(); + $header = $this->factory->createDateHeader('X-Date', $dateTime); + $this->assertEquals($dateTime, $header->getFieldBodyModel()); + } + + public function testTextHeaderHasCorrectType() + { + $header = $this->factory->createTextHeader('X-Foo'); + $this->assertInstanceOf('Swift_Mime_Headers_UnstructuredHeader', $header); + } + + public function testTextHeaderHasCorrectName() + { + $header = $this->factory->createTextHeader('X-Foo'); + $this->assertEquals('X-Foo', $header->getFieldName()); + } + + public function testTextHeaderHasCorrectModel() + { + $header = $this->factory->createTextHeader('X-Foo', 'bar'); + $this->assertEquals('bar', $header->getFieldBodyModel()); + } + + public function testParameterizedHeaderHasCorrectType() + { + $header = $this->factory->createParameterizedHeader('X-Foo'); + $this->assertInstanceOf('Swift_Mime_Headers_ParameterizedHeader', $header); + } + + public function testParameterizedHeaderHasCorrectName() + { + $header = $this->factory->createParameterizedHeader('X-Foo'); + $this->assertEquals('X-Foo', $header->getFieldName()); + } + + public function testParameterizedHeaderHasCorrectModel() + { + $header = $this->factory->createParameterizedHeader('X-Foo', 'bar'); + $this->assertEquals('bar', $header->getFieldBodyModel()); + } + + public function testParameterizedHeaderHasCorrectParams() + { + $header = $this->factory->createParameterizedHeader('X-Foo', 'bar', + array('zip' => 'button') + ); + $this->assertEquals(array('zip' => 'button'), $header->getParameters()); + } + + public function testIdHeaderHasCorrectType() + { + $header = $this->factory->createIdHeader('X-ID'); + $this->assertInstanceOf('Swift_Mime_Headers_IdentificationHeader', $header); + } + + public function testIdHeaderHasCorrectName() + { + $header = $this->factory->createIdHeader('X-ID'); + $this->assertEquals('X-ID', $header->getFieldName()); + } + + public function testIdHeaderHasCorrectModel() + { + $header = $this->factory->createIdHeader('X-ID', 'xyz@abc'); + $this->assertEquals(array('xyz@abc'), $header->getFieldBodyModel()); + } + + public function testPathHeaderHasCorrectType() + { + $header = $this->factory->createPathHeader('X-Path'); + $this->assertInstanceOf('Swift_Mime_Headers_PathHeader', $header); + } + + public function testPathHeaderHasCorrectName() + { + $header = $this->factory->createPathHeader('X-Path'); + $this->assertEquals('X-Path', $header->getFieldName()); + } + + public function testPathHeaderHasCorrectModel() + { + $header = $this->factory->createPathHeader('X-Path', 'foo@bar'); + $this->assertEquals('foo@bar', $header->getFieldBodyModel()); + } + + public function testCharsetChangeNotificationNotifiesEncoders() + { + $encoder = $this->createHeaderEncoder(); + $encoder->expects($this->once()) + ->method('charsetChanged') + ->with('utf-8'); + $paramEncoder = $this->createParamEncoder(); + $paramEncoder->expects($this->once()) + ->method('charsetChanged') + ->with('utf-8'); + + $factory = $this->createFactory($encoder, $paramEncoder); + + $factory->charsetChanged('utf-8'); + } + + private function createFactory($encoder = null, $paramEncoder = null) + { + return new Swift_Mime_SimpleHeaderFactory( + $encoder + ? $encoder : $this->createHeaderEncoder(), + $paramEncoder + ? $paramEncoder : $this->createParamEncoder(), + new EmailValidator() + ); + } + + private function createHeaderEncoder() + { + return $this->getMockBuilder('Swift_Mime_HeaderEncoder')->getMock(); + } + + private function createParamEncoder() + { + return $this->getMockBuilder('Swift_Encoder')->getMock(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleHeaderSetTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleHeaderSetTest.php new file mode 100644 index 00000000..e9dea811 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleHeaderSetTest.php @@ -0,0 +1,734 @@ +createFactory(); + $factory->expects($this->once()) + ->method('createMailboxHeader') + ->with('From', array('person@domain' => 'Person')) + ->will($this->returnValue($this->createHeader('From'))); + + $set = $this->createSet($factory); + $set->addMailboxHeader('From', array('person@domain' => 'Person')); + } + + public function testAddDateHeaderDelegatesToFactory() + { + $dateTime = new DateTimeImmutable(); + + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createDateHeader') + ->with('Date', $dateTime) + ->will($this->returnValue($this->createHeader('Date'))); + + $set = $this->createSet($factory); + $set->addDateHeader('Date', $dateTime); + } + + public function testAddTextHeaderDelegatesToFactory() + { + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createTextHeader') + ->with('Subject', 'some text') + ->will($this->returnValue($this->createHeader('Subject'))); + + $set = $this->createSet($factory); + $set->addTextHeader('Subject', 'some text'); + } + + public function testAddParameterizedHeaderDelegatesToFactory() + { + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createParameterizedHeader') + ->with('Content-Type', 'text/plain', array('charset' => 'utf-8')) + ->will($this->returnValue($this->createHeader('Content-Type'))); + + $set = $this->createSet($factory); + $set->addParameterizedHeader('Content-Type', 'text/plain', + array('charset' => 'utf-8') + ); + } + + public function testAddIdHeaderDelegatesToFactory() + { + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($this->createHeader('Message-ID'))); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + } + + public function testAddPathHeaderDelegatesToFactory() + { + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createPathHeader') + ->with('Return-Path', 'some@path') + ->will($this->returnValue($this->createHeader('Return-Path'))); + + $set = $this->createSet($factory); + $set->addPathHeader('Return-Path', 'some@path'); + } + + public function testHasReturnsFalseWhenNoHeaders() + { + $set = $this->createSet($this->createFactory()); + $this->assertFalse($set->has('Some-Header')); + } + + public function testAddedMailboxHeaderIsSeenByHas() + { + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createMailboxHeader') + ->with('From', array('person@domain' => 'Person')) + ->will($this->returnValue($this->createHeader('From'))); + + $set = $this->createSet($factory); + $set->addMailboxHeader('From', array('person@domain' => 'Person')); + $this->assertTrue($set->has('From')); + } + + public function testAddedDateHeaderIsSeenByHas() + { + $dateTime = new DateTimeImmutable(); + + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createDateHeader') + ->with('Date', $dateTime) + ->will($this->returnValue($this->createHeader('Date'))); + + $set = $this->createSet($factory); + $set->addDateHeader('Date', $dateTime); + $this->assertTrue($set->has('Date')); + } + + public function testAddedTextHeaderIsSeenByHas() + { + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createTextHeader') + ->with('Subject', 'some text') + ->will($this->returnValue($this->createHeader('Subject'))); + + $set = $this->createSet($factory); + $set->addTextHeader('Subject', 'some text'); + $this->assertTrue($set->has('Subject')); + } + + public function testAddedParameterizedHeaderIsSeenByHas() + { + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createParameterizedHeader') + ->with('Content-Type', 'text/plain', array('charset' => 'utf-8')) + ->will($this->returnValue($this->createHeader('Content-Type'))); + + $set = $this->createSet($factory); + $set->addParameterizedHeader('Content-Type', 'text/plain', + array('charset' => 'utf-8') + ); + $this->assertTrue($set->has('Content-Type')); + } + + public function testAddedIdHeaderIsSeenByHas() + { + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($this->createHeader('Message-ID'))); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $this->assertTrue($set->has('Message-ID')); + } + + public function testAddedPathHeaderIsSeenByHas() + { + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createPathHeader') + ->with('Return-Path', 'some@path') + ->will($this->returnValue($this->createHeader('Return-Path'))); + + $set = $this->createSet($factory); + $set->addPathHeader('Return-Path', 'some@path'); + $this->assertTrue($set->has('Return-Path')); + } + + public function testNewlySetHeaderIsSeenByHas() + { + $factory = $this->createFactory(); + $header = $this->createHeader('X-Foo', 'bar'); + $set = $this->createSet($factory); + $set->set($header); + $this->assertTrue($set->has('X-Foo')); + } + + public function testHasCanAcceptOffset() + { + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($this->createHeader('Message-ID'))); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $this->assertTrue($set->has('Message-ID', 0)); + } + + public function testHasWithIllegalOffsetReturnsFalse() + { + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($this->createHeader('Message-ID'))); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $this->assertFalse($set->has('Message-ID', 1)); + } + + public function testHasCanDistinguishMultipleHeaders() + { + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($this->createHeader('Message-ID'))); + $factory->expects($this->at(1)) + ->method('createIdHeader') + ->with('Message-ID', 'other@id') + ->will($this->returnValue($this->createHeader('Message-ID'))); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $set->addIdHeader('Message-ID', 'other@id'); + $this->assertTrue($set->has('Message-ID', 1)); + } + + public function testGetWithUnspecifiedOffset() + { + $header = $this->createHeader('Message-ID'); + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $this->assertSame($header, $set->get('Message-ID')); + } + + public function testGetWithSpeiciedOffset() + { + $header0 = $this->createHeader('Message-ID'); + $header1 = $this->createHeader('Message-ID'); + $header2 = $this->createHeader('Message-ID'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header0)); + $factory->expects($this->at(1)) + ->method('createIdHeader') + ->with('Message-ID', 'other@id') + ->will($this->returnValue($header1)); + $factory->expects($this->at(2)) + ->method('createIdHeader') + ->with('Message-ID', 'more@id') + ->will($this->returnValue($header2)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $set->addIdHeader('Message-ID', 'other@id'); + $set->addIdHeader('Message-ID', 'more@id'); + $this->assertSame($header1, $set->get('Message-ID', 1)); + } + + public function testGetReturnsNullIfHeaderNotSet() + { + $set = $this->createSet($this->createFactory()); + $this->assertNull($set->get('Message-ID', 99)); + } + + public function testGetAllReturnsAllHeadersMatchingName() + { + $header0 = $this->createHeader('Message-ID'); + $header1 = $this->createHeader('Message-ID'); + $header2 = $this->createHeader('Message-ID'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header0)); + $factory->expects($this->at(1)) + ->method('createIdHeader') + ->with('Message-ID', 'other@id') + ->will($this->returnValue($header1)); + $factory->expects($this->at(2)) + ->method('createIdHeader') + ->with('Message-ID', 'more@id') + ->will($this->returnValue($header2)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $set->addIdHeader('Message-ID', 'other@id'); + $set->addIdHeader('Message-ID', 'more@id'); + + $this->assertEquals(array($header0, $header1, $header2), + $set->getAll('Message-ID') + ); + } + + public function testGetAllReturnsAllHeadersIfNoArguments() + { + $header0 = $this->createHeader('Message-ID'); + $header1 = $this->createHeader('Subject'); + $header2 = $this->createHeader('To'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header0)); + $factory->expects($this->at(1)) + ->method('createIdHeader') + ->with('Subject', 'thing') + ->will($this->returnValue($header1)); + $factory->expects($this->at(2)) + ->method('createIdHeader') + ->with('To', 'person@example.org') + ->will($this->returnValue($header2)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $set->addIdHeader('Subject', 'thing'); + $set->addIdHeader('To', 'person@example.org'); + + $this->assertEquals(array($header0, $header1, $header2), + $set->getAll() + ); + } + + public function testGetAllReturnsEmptyArrayIfNoneSet() + { + $set = $this->createSet($this->createFactory()); + $this->assertEquals(array(), $set->getAll('Received')); + } + + public function testRemoveWithUnspecifiedOffset() + { + $header = $this->createHeader('Message-ID'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $set->remove('Message-ID'); + $this->assertFalse($set->has('Message-ID')); + } + + public function testRemoveWithSpecifiedIndexRemovesHeader() + { + $header0 = $this->createHeader('Message-ID'); + $header1 = $this->createHeader('Message-ID'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header0)); + $factory->expects($this->at(1)) + ->method('createIdHeader') + ->with('Message-ID', 'other@id') + ->will($this->returnValue($header1)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $set->addIdHeader('Message-ID', 'other@id'); + $set->remove('Message-ID', 0); + $this->assertFalse($set->has('Message-ID', 0)); + $this->assertTrue($set->has('Message-ID', 1)); + $this->assertTrue($set->has('Message-ID')); + $set->remove('Message-ID', 1); + $this->assertFalse($set->has('Message-ID', 1)); + $this->assertFalse($set->has('Message-ID')); + } + + public function testRemoveWithSpecifiedIndexLeavesOtherHeaders() + { + $header0 = $this->createHeader('Message-ID'); + $header1 = $this->createHeader('Message-ID'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header0)); + $factory->expects($this->at(1)) + ->method('createIdHeader') + ->with('Message-ID', 'other@id') + ->will($this->returnValue($header1)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $set->addIdHeader('Message-ID', 'other@id'); + $set->remove('Message-ID', 1); + $this->assertTrue($set->has('Message-ID', 0)); + } + + public function testRemoveWithInvalidOffsetDoesNothing() + { + $header = $this->createHeader('Message-ID'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $set->remove('Message-ID', 50); + $this->assertTrue($set->has('Message-ID')); + } + + public function testRemoveAllRemovesAllHeadersWithName() + { + $header0 = $this->createHeader('Message-ID'); + $header1 = $this->createHeader('Message-ID'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header0)); + $factory->expects($this->at(1)) + ->method('createIdHeader') + ->with('Message-ID', 'other@id') + ->will($this->returnValue($header1)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $set->addIdHeader('Message-ID', 'other@id'); + $set->removeAll('Message-ID'); + $this->assertFalse($set->has('Message-ID', 0)); + $this->assertFalse($set->has('Message-ID', 1)); + } + + public function testHasIsNotCaseSensitive() + { + $header = $this->createHeader('Message-ID'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $this->assertTrue($set->has('message-id')); + } + + public function testGetIsNotCaseSensitive() + { + $header = $this->createHeader('Message-ID'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $this->assertSame($header, $set->get('message-id')); + } + + public function testGetAllIsNotCaseSensitive() + { + $header = $this->createHeader('Message-ID'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $this->assertEquals(array($header), $set->getAll('message-id')); + } + + public function testRemoveIsNotCaseSensitive() + { + $header = $this->createHeader('Message-ID'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $set->remove('message-id'); + $this->assertFalse($set->has('Message-ID')); + } + + public function testRemoveAllIsNotCaseSensitive() + { + $header = $this->createHeader('Message-ID'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createIdHeader') + ->with('Message-ID', 'some@id') + ->will($this->returnValue($header)); + + $set = $this->createSet($factory); + $set->addIdHeader('Message-ID', 'some@id'); + $set->removeAll('message-id'); + $this->assertFalse($set->has('Message-ID')); + } + + public function testToStringJoinsHeadersTogether() + { + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createTextHeader') + ->with('Foo', 'bar') + ->will($this->returnValue($this->createHeader('Foo', 'bar'))); + $factory->expects($this->at(1)) + ->method('createTextHeader') + ->with('Zip', 'buttons') + ->will($this->returnValue($this->createHeader('Zip', 'buttons'))); + + $set = $this->createSet($factory); + $set->addTextHeader('Foo', 'bar'); + $set->addTextHeader('Zip', 'buttons'); + $this->assertEquals( + "Foo: bar\r\n". + "Zip: buttons\r\n", + $set->toString() + ); + } + + public function testHeadersWithoutBodiesAreNotDisplayed() + { + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createTextHeader') + ->with('Foo', 'bar') + ->will($this->returnValue($this->createHeader('Foo', 'bar'))); + $factory->expects($this->at(1)) + ->method('createTextHeader') + ->with('Zip', '') + ->will($this->returnValue($this->createHeader('Zip', ''))); + + $set = $this->createSet($factory); + $set->addTextHeader('Foo', 'bar'); + $set->addTextHeader('Zip', ''); + $this->assertEquals( + "Foo: bar\r\n", + $set->toString() + ); + } + + public function testHeadersWithoutBodiesCanBeForcedToDisplay() + { + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createTextHeader') + ->with('Foo', '') + ->will($this->returnValue($this->createHeader('Foo', ''))); + $factory->expects($this->at(1)) + ->method('createTextHeader') + ->with('Zip', '') + ->will($this->returnValue($this->createHeader('Zip', ''))); + + $set = $this->createSet($factory); + $set->addTextHeader('Foo', ''); + $set->addTextHeader('Zip', ''); + $set->setAlwaysDisplayed(array('Foo', 'Zip')); + $this->assertEquals( + "Foo: \r\n". + "Zip: \r\n", + $set->toString() + ); + } + + public function testHeaderSequencesCanBeSpecified() + { + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createTextHeader') + ->with('Third', 'three') + ->will($this->returnValue($this->createHeader('Third', 'three'))); + $factory->expects($this->at(1)) + ->method('createTextHeader') + ->with('First', 'one') + ->will($this->returnValue($this->createHeader('First', 'one'))); + $factory->expects($this->at(2)) + ->method('createTextHeader') + ->with('Second', 'two') + ->will($this->returnValue($this->createHeader('Second', 'two'))); + + $set = $this->createSet($factory); + $set->addTextHeader('Third', 'three'); + $set->addTextHeader('First', 'one'); + $set->addTextHeader('Second', 'two'); + + $set->defineOrdering(array('First', 'Second', 'Third')); + + $this->assertEquals( + "First: one\r\n". + "Second: two\r\n". + "Third: three\r\n", + $set->toString() + ); + } + + public function testUnsortedHeadersAppearAtEnd() + { + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createTextHeader') + ->with('Fourth', 'four') + ->will($this->returnValue($this->createHeader('Fourth', 'four'))); + $factory->expects($this->at(1)) + ->method('createTextHeader') + ->with('Fifth', 'five') + ->will($this->returnValue($this->createHeader('Fifth', 'five'))); + $factory->expects($this->at(2)) + ->method('createTextHeader') + ->with('Third', 'three') + ->will($this->returnValue($this->createHeader('Third', 'three'))); + $factory->expects($this->at(3)) + ->method('createTextHeader') + ->with('First', 'one') + ->will($this->returnValue($this->createHeader('First', 'one'))); + $factory->expects($this->at(4)) + ->method('createTextHeader') + ->with('Second', 'two') + ->will($this->returnValue($this->createHeader('Second', 'two'))); + + $set = $this->createSet($factory); + $set->addTextHeader('Fourth', 'four'); + $set->addTextHeader('Fifth', 'five'); + $set->addTextHeader('Third', 'three'); + $set->addTextHeader('First', 'one'); + $set->addTextHeader('Second', 'two'); + + $set->defineOrdering(array('First', 'Second', 'Third')); + + $this->assertEquals( + "First: one\r\n". + "Second: two\r\n". + "Third: three\r\n". + "Fourth: four\r\n". + "Fifth: five\r\n", + $set->toString() + ); + } + + public function testSettingCharsetNotifiesAlreadyExistingHeaders() + { + $subject = $this->createHeader('Subject', 'some text'); + $xHeader = $this->createHeader('X-Header', 'some text'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createTextHeader') + ->with('Subject', 'some text') + ->will($this->returnValue($subject)); + $factory->expects($this->at(1)) + ->method('createTextHeader') + ->with('X-Header', 'some text') + ->will($this->returnValue($xHeader)); + $subject->expects($this->once()) + ->method('setCharset') + ->with('utf-8'); + $xHeader->expects($this->once()) + ->method('setCharset') + ->with('utf-8'); + + $set = $this->createSet($factory); + $set->addTextHeader('Subject', 'some text'); + $set->addTextHeader('X-Header', 'some text'); + + $set->setCharset('utf-8'); + } + + public function testCharsetChangeNotifiesAlreadyExistingHeaders() + { + $subject = $this->createHeader('Subject', 'some text'); + $xHeader = $this->createHeader('X-Header', 'some text'); + $factory = $this->createFactory(); + $factory->expects($this->at(0)) + ->method('createTextHeader') + ->with('Subject', 'some text') + ->will($this->returnValue($subject)); + $factory->expects($this->at(1)) + ->method('createTextHeader') + ->with('X-Header', 'some text') + ->will($this->returnValue($xHeader)); + $subject->expects($this->once()) + ->method('setCharset') + ->with('utf-8'); + $xHeader->expects($this->once()) + ->method('setCharset') + ->with('utf-8'); + + $set = $this->createSet($factory); + $set->addTextHeader('Subject', 'some text'); + $set->addTextHeader('X-Header', 'some text'); + + $set->charsetChanged('utf-8'); + } + + public function testCharsetChangeNotifiesFactory() + { + $factory = $this->createFactory(); + $factory->expects($this->once()) + ->method('charsetChanged') + ->with('utf-8'); + + $set = $this->createSet($factory); + + $set->setCharset('utf-8'); + } + + private function createSet($factory) + { + return new Swift_Mime_SimpleHeaderSet($factory); + } + + private function createFactory() + { + return $this->getMockBuilder('Swift_Mime_SimpleHeaderFactory')->disableOriginalConstructor()->getMock(); + } + + private function createHeader($name, $body = '') + { + $header = $this->getMockBuilder('Swift_Mime_Header')->getMock(); + $header->expects($this->any()) + ->method('getFieldName') + ->will($this->returnValue($name)); + $header->expects($this->any()) + ->method('toString') + ->will($this->returnValue(sprintf("%s: %s\r\n", $name, $body))); + $header->expects($this->any()) + ->method('getFieldBody') + ->will($this->returnValue($body)); + + return $header; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleMessageTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleMessageTest.php new file mode 100644 index 00000000..1be4c5ec --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleMessageTest.php @@ -0,0 +1,837 @@ +addToAssertionCount(1); + } + + public function testNestingLevelIsTop() + { + $message = $this->createMessage($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals( + Swift_Mime_SimpleMimeEntity::LEVEL_TOP, $message->getNestingLevel() + ); + } + + public function testDateIsReturnedFromHeader() + { + $dateTime = new DateTimeImmutable(); + + $date = $this->createHeader('Date', $dateTime); + $message = $this->createMessage( + $this->createHeaderSet(array('Date' => $date)), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals($dateTime, $message->getDate()); + } + + public function testDateIsSetInHeader() + { + $dateTime = new DateTimeImmutable(); + + $date = $this->createHeader('Date', new DateTimeImmutable(), array(), false); + $date->shouldReceive('setFieldBodyModel') + ->once() + ->with($dateTime); + $date->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes(); + + $message = $this->createMessage( + $this->createHeaderSet(array('Date' => $date)), + $this->createEncoder(), $this->createCache() + ); + $message->setDate($dateTime); + } + + public function testDateHeaderIsCreatedIfNonePresent() + { + $dateTime = new DateTimeImmutable(); + + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addDateHeader') + ->once() + ->with('Date', $dateTime); + $headers->shouldReceive('addDateHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setDate($dateTime); + } + + public function testDateHeaderIsAddedDuringConstruction() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addDateHeader') + ->once() + ->with('Date', Mockery::type('DateTimeImmutable')); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + } + + public function testIdIsReturnedFromHeader() + { + /* -- RFC 2045, 7. + In constructing a high-level user agent, it may be desirable to allow + one body to make reference to another. Accordingly, bodies may be + labelled using the "Content-ID" header field, which is syntactically + identical to the "Message-ID" header field + */ + + $messageId = $this->createHeader('Message-ID', 'a@b'); + $message = $this->createMessage( + $this->createHeaderSet(array('Message-ID' => $messageId)), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals('a@b', $message->getId()); + } + + public function testIdIsSetInHeader() + { + $messageId = $this->createHeader('Message-ID', 'a@b', array(), false); + $messageId->shouldReceive('setFieldBodyModel') + ->once() + ->with('x@y'); + $messageId->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes(); + + $message = $this->createMessage( + $this->createHeaderSet(array('Message-ID' => $messageId)), + $this->createEncoder(), $this->createCache() + ); + $message->setId('x@y'); + } + + public function testIdIsAutoGenerated() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addIdHeader') + ->once() + ->with('Message-ID', '/^.*?@.*?$/D'); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + } + + public function testSubjectIsReturnedFromHeader() + { + /* -- RFC 2822, 3.6.5. + */ + + $subject = $this->createHeader('Subject', 'example subject'); + $message = $this->createMessage( + $this->createHeaderSet(array('Subject' => $subject)), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals('example subject', $message->getSubject()); + } + + public function testSubjectIsSetInHeader() + { + $subject = $this->createHeader('Subject', '', array(), false); + $subject->shouldReceive('setFieldBodyModel') + ->once() + ->with('foo'); + + $message = $this->createMessage( + $this->createHeaderSet(array('Subject' => $subject)), + $this->createEncoder(), $this->createCache() + ); + $message->setSubject('foo'); + } + + public function testSubjectHeaderIsCreatedIfNotPresent() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addTextHeader') + ->once() + ->with('Subject', 'example subject'); + $headers->shouldReceive('addTextHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setSubject('example subject'); + } + + public function testReturnPathIsReturnedFromHeader() + { + /* -- RFC 2822, 3.6.7. + */ + + $path = $this->createHeader('Return-Path', 'bounces@domain'); + $message = $this->createMessage( + $this->createHeaderSet(array('Return-Path' => $path)), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals('bounces@domain', $message->getReturnPath()); + } + + public function testReturnPathIsSetInHeader() + { + $path = $this->createHeader('Return-Path', '', array(), false); + $path->shouldReceive('setFieldBodyModel') + ->once() + ->with('bounces@domain'); + + $message = $this->createMessage( + $this->createHeaderSet(array('Return-Path' => $path)), + $this->createEncoder(), $this->createCache() + ); + $message->setReturnPath('bounces@domain'); + } + + public function testReturnPathHeaderIsAddedIfNoneSet() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addPathHeader') + ->once() + ->with('Return-Path', 'bounces@domain'); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setReturnPath('bounces@domain'); + } + + public function testSenderIsReturnedFromHeader() + { + /* -- RFC 2822, 3.6.2. + */ + + $sender = $this->createHeader('Sender', array('sender@domain' => 'Name')); + $message = $this->createMessage( + $this->createHeaderSet(array('Sender' => $sender)), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals(array('sender@domain' => 'Name'), $message->getSender()); + } + + public function testSenderIsSetInHeader() + { + $sender = $this->createHeader('Sender', array('sender@domain' => 'Name'), + array(), false + ); + $sender->shouldReceive('setFieldBodyModel') + ->once() + ->with(array('other@domain' => 'Other')); + + $message = $this->createMessage( + $this->createHeaderSet(array('Sender' => $sender)), + $this->createEncoder(), $this->createCache() + ); + $message->setSender(array('other@domain' => 'Other')); + } + + public function testSenderHeaderIsAddedIfNoneSet() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addMailboxHeader') + ->once() + ->with('Sender', (array) 'sender@domain'); + $headers->shouldReceive('addMailboxHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setSender('sender@domain'); + } + + public function testNameCanBeUsedInSenderHeader() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addMailboxHeader') + ->once() + ->with('Sender', array('sender@domain' => 'Name')); + $headers->shouldReceive('addMailboxHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setSender('sender@domain', 'Name'); + } + + public function testFromIsReturnedFromHeader() + { + /* -- RFC 2822, 3.6.2. + */ + + $from = $this->createHeader('From', array('from@domain' => 'Name')); + $message = $this->createMessage( + $this->createHeaderSet(array('From' => $from)), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals(array('from@domain' => 'Name'), $message->getFrom()); + } + + public function testFromIsSetInHeader() + { + $from = $this->createHeader('From', array('from@domain' => 'Name'), + array(), false + ); + $from->shouldReceive('setFieldBodyModel') + ->once() + ->with(array('other@domain' => 'Other')); + + $message = $this->createMessage( + $this->createHeaderSet(array('From' => $from)), + $this->createEncoder(), $this->createCache() + ); + $message->setFrom(array('other@domain' => 'Other')); + } + + public function testFromIsAddedToHeadersDuringAddFrom() + { + $from = $this->createHeader('From', array('from@domain' => 'Name'), + array(), false + ); + $from->shouldReceive('setFieldBodyModel') + ->once() + ->with(array('from@domain' => 'Name', 'other@domain' => 'Other')); + + $message = $this->createMessage( + $this->createHeaderSet(array('From' => $from)), + $this->createEncoder(), $this->createCache() + ); + $message->addFrom('other@domain', 'Other'); + } + + public function testFromHeaderIsAddedIfNoneSet() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addMailboxHeader') + ->once() + ->with('From', (array) 'from@domain'); + $headers->shouldReceive('addMailboxHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setFrom('from@domain'); + } + + public function testPersonalNameCanBeUsedInFromAddress() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addMailboxHeader') + ->once() + ->with('From', array('from@domain' => 'Name')); + $headers->shouldReceive('addMailboxHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setFrom('from@domain', 'Name'); + } + + public function testReplyToIsReturnedFromHeader() + { + /* -- RFC 2822, 3.6.2. + */ + + $reply = $this->createHeader('Reply-To', array('reply@domain' => 'Name')); + $message = $this->createMessage( + $this->createHeaderSet(array('Reply-To' => $reply)), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals(array('reply@domain' => 'Name'), $message->getReplyTo()); + } + + public function testReplyToIsSetInHeader() + { + $reply = $this->createHeader('Reply-To', array('reply@domain' => 'Name'), + array(), false + ); + $reply->shouldReceive('setFieldBodyModel') + ->once() + ->with(array('other@domain' => 'Other')); + + $message = $this->createMessage( + $this->createHeaderSet(array('Reply-To' => $reply)), + $this->createEncoder(), $this->createCache() + ); + $message->setReplyTo(array('other@domain' => 'Other')); + } + + public function testReplyToIsAddedToHeadersDuringAddReplyTo() + { + $replyTo = $this->createHeader('Reply-To', array('from@domain' => 'Name'), + array(), false + ); + $replyTo->shouldReceive('setFieldBodyModel') + ->once() + ->with(array('from@domain' => 'Name', 'other@domain' => 'Other')); + + $message = $this->createMessage( + $this->createHeaderSet(array('Reply-To' => $replyTo)), + $this->createEncoder(), $this->createCache() + ); + $message->addReplyTo('other@domain', 'Other'); + } + + public function testReplyToHeaderIsAddedIfNoneSet() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addMailboxHeader') + ->once() + ->with('Reply-To', (array) 'reply@domain'); + $headers->shouldReceive('addMailboxHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setReplyTo('reply@domain'); + } + + public function testNameCanBeUsedInReplyTo() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addMailboxHeader') + ->once() + ->with('Reply-To', array('reply@domain' => 'Name')); + $headers->shouldReceive('addMailboxHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setReplyTo('reply@domain', 'Name'); + } + + public function testToIsReturnedFromHeader() + { + /* -- RFC 2822, 3.6.3. + */ + + $to = $this->createHeader('To', array('to@domain' => 'Name')); + $message = $this->createMessage( + $this->createHeaderSet(array('To' => $to)), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals(array('to@domain' => 'Name'), $message->getTo()); + } + + public function testToIsSetInHeader() + { + $to = $this->createHeader('To', array('to@domain' => 'Name'), + array(), false + ); + $to->shouldReceive('setFieldBodyModel') + ->once() + ->with(array('other@domain' => 'Other')); + + $message = $this->createMessage( + $this->createHeaderSet(array('To' => $to)), + $this->createEncoder(), $this->createCache() + ); + $message->setTo(array('other@domain' => 'Other')); + } + + public function testToIsAddedToHeadersDuringAddTo() + { + $to = $this->createHeader('To', array('from@domain' => 'Name'), + array(), false + ); + $to->shouldReceive('setFieldBodyModel') + ->once() + ->with(array('from@domain' => 'Name', 'other@domain' => 'Other')); + + $message = $this->createMessage( + $this->createHeaderSet(array('To' => $to)), + $this->createEncoder(), $this->createCache() + ); + $message->addTo('other@domain', 'Other'); + } + + public function testToHeaderIsAddedIfNoneSet() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addMailboxHeader') + ->once() + ->with('To', (array) 'to@domain'); + $headers->shouldReceive('addMailboxHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setTo('to@domain'); + } + + public function testNameCanBeUsedInToHeader() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addMailboxHeader') + ->once() + ->with('To', array('to@domain' => 'Name')); + $headers->shouldReceive('addMailboxHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setTo('to@domain', 'Name'); + } + + public function testCcIsReturnedFromHeader() + { + /* -- RFC 2822, 3.6.3. + */ + + $cc = $this->createHeader('Cc', array('cc@domain' => 'Name')); + $message = $this->createMessage( + $this->createHeaderSet(array('Cc' => $cc)), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals(array('cc@domain' => 'Name'), $message->getCc()); + } + + public function testCcIsSetInHeader() + { + $cc = $this->createHeader('Cc', array('cc@domain' => 'Name'), + array(), false + ); + $cc->shouldReceive('setFieldBodyModel') + ->once() + ->with(array('other@domain' => 'Other')); + + $message = $this->createMessage( + $this->createHeaderSet(array('Cc' => $cc)), + $this->createEncoder(), $this->createCache() + ); + $message->setCc(array('other@domain' => 'Other')); + } + + public function testCcIsAddedToHeadersDuringAddCc() + { + $cc = $this->createHeader('Cc', array('from@domain' => 'Name'), + array(), false + ); + $cc->shouldReceive('setFieldBodyModel') + ->once() + ->with(array('from@domain' => 'Name', 'other@domain' => 'Other')); + + $message = $this->createMessage( + $this->createHeaderSet(array('Cc' => $cc)), + $this->createEncoder(), $this->createCache() + ); + $message->addCc('other@domain', 'Other'); + } + + public function testCcHeaderIsAddedIfNoneSet() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addMailboxHeader') + ->once() + ->with('Cc', (array) 'cc@domain'); + $headers->shouldReceive('addMailboxHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setCc('cc@domain'); + } + + public function testNameCanBeUsedInCcHeader() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addMailboxHeader') + ->once() + ->with('Cc', array('cc@domain' => 'Name')); + $headers->shouldReceive('addMailboxHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setCc('cc@domain', 'Name'); + } + + public function testBccIsReturnedFromHeader() + { + /* -- RFC 2822, 3.6.3. + */ + + $bcc = $this->createHeader('Bcc', array('bcc@domain' => 'Name')); + $message = $this->createMessage( + $this->createHeaderSet(array('Bcc' => $bcc)), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals(array('bcc@domain' => 'Name'), $message->getBcc()); + } + + public function testBccIsSetInHeader() + { + $bcc = $this->createHeader('Bcc', array('bcc@domain' => 'Name'), + array(), false + ); + $bcc->shouldReceive('setFieldBodyModel') + ->once() + ->with(array('other@domain' => 'Other')); + + $message = $this->createMessage( + $this->createHeaderSet(array('Bcc' => $bcc)), + $this->createEncoder(), $this->createCache() + ); + $message->setBcc(array('other@domain' => 'Other')); + } + + public function testBccIsAddedToHeadersDuringAddBcc() + { + $bcc = $this->createHeader('Bcc', array('from@domain' => 'Name'), + array(), false + ); + $bcc->shouldReceive('setFieldBodyModel') + ->once() + ->with(array('from@domain' => 'Name', 'other@domain' => 'Other')); + + $message = $this->createMessage( + $this->createHeaderSet(array('Bcc' => $bcc)), + $this->createEncoder(), $this->createCache() + ); + $message->addBcc('other@domain', 'Other'); + } + + public function testBccHeaderIsAddedIfNoneSet() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addMailboxHeader') + ->once() + ->with('Bcc', (array) 'bcc@domain'); + $headers->shouldReceive('addMailboxHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setBcc('bcc@domain'); + } + + public function testNameCanBeUsedInBcc() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addMailboxHeader') + ->once() + ->with('Bcc', array('bcc@domain' => 'Name')); + $headers->shouldReceive('addMailboxHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setBcc('bcc@domain', 'Name'); + } + + public function testPriorityIsReadFromHeader() + { + $prio = $this->createHeader('X-Priority', '2 (High)'); + $message = $this->createMessage( + $this->createHeaderSet(array('X-Priority' => $prio)), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals(2, $message->getPriority()); + } + + public function testPriorityIsSetInHeader() + { + $prio = $this->createHeader('X-Priority', '2 (High)', array(), false); + $prio->shouldReceive('setFieldBodyModel') + ->once() + ->with('5 (Lowest)'); + + $message = $this->createMessage( + $this->createHeaderSet(array('X-Priority' => $prio)), + $this->createEncoder(), $this->createCache() + ); + $message->setPriority($message::PRIORITY_LOWEST); + } + + public function testPriorityHeaderIsAddedIfNoneSet() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addTextHeader') + ->once() + ->with('X-Priority', '4 (Low)'); + $headers->shouldReceive('addTextHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setPriority($message::PRIORITY_LOW); + } + + public function testReadReceiptAddressReadFromHeader() + { + $rcpt = $this->createHeader('Disposition-Notification-To', + array('chris@swiftmailer.org' => 'Chris') + ); + $message = $this->createMessage( + $this->createHeaderSet(array('Disposition-Notification-To' => $rcpt)), + $this->createEncoder(), $this->createCache() + ); + $this->assertEquals(array('chris@swiftmailer.org' => 'Chris'), + $message->getReadReceiptTo() + ); + } + + public function testReadReceiptIsSetInHeader() + { + $rcpt = $this->createHeader('Disposition-Notification-To', array(), array(), false); + $rcpt->shouldReceive('setFieldBodyModel') + ->once() + ->with('mark@swiftmailer.org'); + + $message = $this->createMessage( + $this->createHeaderSet(array('Disposition-Notification-To' => $rcpt)), + $this->createEncoder(), $this->createCache() + ); + $message->setReadReceiptTo('mark@swiftmailer.org'); + } + + public function testReadReceiptHeaderIsAddedIfNoneSet() + { + $headers = $this->createHeaderSet(array(), false); + $headers->shouldReceive('addMailboxHeader') + ->once() + ->with('Disposition-Notification-To', 'mark@swiftmailer.org'); + $headers->shouldReceive('addMailboxHeader') + ->zeroOrMoreTimes(); + + $message = $this->createMessage($headers, $this->createEncoder(), + $this->createCache() + ); + $message->setReadReceiptTo('mark@swiftmailer.org'); + } + + public function testChildrenCanBeAttached() + { + $child1 = $this->createChild(); + $child2 = $this->createChild(); + + $message = $this->createMessage($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + + $message->attach($child1); + $message->attach($child2); + + $this->assertEquals(array($child1, $child2), $message->getChildren()); + } + + public function testChildrenCanBeDetached() + { + $child1 = $this->createChild(); + $child2 = $this->createChild(); + + $message = $this->createMessage($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + + $message->attach($child1); + $message->attach($child2); + + $message->detach($child1); + + $this->assertEquals(array($child2), $message->getChildren()); + } + + public function testEmbedAttachesChild() + { + $child = $this->createChild(); + + $message = $this->createMessage($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + + $message->embed($child); + + $this->assertEquals(array($child), $message->getChildren()); + } + + public function testEmbedReturnsValidCid() + { + $child = $this->createChild(Swift_Mime_SimpleMimeEntity::LEVEL_RELATED, '', + false + ); + $child->shouldReceive('getId') + ->zeroOrMoreTimes() + ->andReturn('foo@bar'); + + $message = $this->createMessage($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + + $this->assertEquals('cid:foo@bar', $message->embed($child)); + } + + public function testFluidInterface() + { + $child = $this->createChild(); + $message = $this->createMessage($this->createHeaderSet(), + $this->createEncoder(), $this->createCache() + ); + $this->assertSame($message, + $message + ->setContentType('text/plain') + ->setEncoder($this->createEncoder()) + ->setId('foo@bar') + ->setDescription('my description') + ->setMaxLineLength(998) + ->setBody('xx') + ->setBoundary('xyz') + ->setChildren(array()) + ->setCharset('iso-8859-1') + ->setFormat('flowed') + ->setDelSp(false) + ->setSubject('subj') + ->setDate(new DateTimeImmutable()) + ->setReturnPath('foo@bar') + ->setSender('foo@bar') + ->setFrom(array('x@y' => 'XY')) + ->setReplyTo(array('ab@cd' => 'ABCD')) + ->setTo(array('chris@site.tld', 'mark@site.tld')) + ->setCc('john@somewhere.tld') + ->setBcc(array('one@site', 'two@site' => 'Two')) + ->setPriority($message::PRIORITY_LOW) + ->setReadReceiptTo('a@b') + ->attach($child) + ->detach($child) + ); + } + + //abstract + protected function createEntity($headers, $encoder, $cache) + { + return $this->createMessage($headers, $encoder, $cache); + } + + protected function createMimePart($headers, $encoder, $cache) + { + return $this->createMessage($headers, $encoder, $cache); + } + + private function createMessage($headers, $encoder, $cache) + { + $idGenerator = new Swift_Mime_IdGenerator('example.com'); + + return new Swift_Mime_SimpleMessage($headers, $encoder, $cache, $idGenerator); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleMimeEntityTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleMimeEntityTest.php new file mode 100644 index 00000000..24578ed8 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Mime/SimpleMimeEntityTest.php @@ -0,0 +1,12 @@ +assertEquals(10, $plugin->getThreshold()); + $plugin->setThreshold(100); + $this->assertEquals(100, $plugin->getThreshold()); + } + + public function testSleepTimeCanBeSetAndFetched() + { + $plugin = new Swift_Plugins_AntiFloodPlugin(10, 5); + $this->assertEquals(5, $plugin->getSleepTime()); + $plugin->setSleepTime(1); + $this->assertEquals(1, $plugin->getSleepTime()); + } + + public function testPluginStopsConnectionAfterThreshold() + { + $transport = $this->createTransport(); + $transport->expects($this->once()) + ->method('start'); + $transport->expects($this->once()) + ->method('stop'); + + $evt = $this->createSendEvent($transport); + + $plugin = new Swift_Plugins_AntiFloodPlugin(10); + for ($i = 0; $i < 12; ++$i) { + $plugin->sendPerformed($evt); + } + } + + public function testPluginCanStopAndStartMultipleTimes() + { + $transport = $this->createTransport(); + $transport->expects($this->exactly(5)) + ->method('start'); + $transport->expects($this->exactly(5)) + ->method('stop'); + + $evt = $this->createSendEvent($transport); + + $plugin = new Swift_Plugins_AntiFloodPlugin(2); + for ($i = 0; $i < 11; ++$i) { + $plugin->sendPerformed($evt); + } + } + + public function testPluginCanSleepDuringRestart() + { + $sleeper = $this->getMockBuilder('Swift_Plugins_Sleeper')->getMock(); + $sleeper->expects($this->once()) + ->method('sleep') + ->with(10); + + $transport = $this->createTransport(); + $transport->expects($this->once()) + ->method('start'); + $transport->expects($this->once()) + ->method('stop'); + + $evt = $this->createSendEvent($transport); + + $plugin = new Swift_Plugins_AntiFloodPlugin(99, 10, $sleeper); + for ($i = 0; $i < 101; ++$i) { + $plugin->sendPerformed($evt); + } + } + + private function createTransport() + { + return $this->getMockBuilder('Swift_Transport')->getMock(); + } + + private function createSendEvent($transport) + { + $evt = $this->getMockBuilder('Swift_Events_SendEvent') + ->disableOriginalConstructor() + ->getMock(); + $evt->expects($this->any()) + ->method('getSource') + ->will($this->returnValue($transport)); + $evt->expects($this->any()) + ->method('getTransport') + ->will($this->returnValue($transport)); + + return $evt; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/BandwidthMonitorPluginTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/BandwidthMonitorPluginTest.php new file mode 100644 index 00000000..bd65559d --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/BandwidthMonitorPluginTest.php @@ -0,0 +1,128 @@ +monitor = new Swift_Plugins_BandwidthMonitorPlugin(); + } + + public function testBytesOutIncreasesWhenCommandsSent() + { + $evt = $this->createCommandEvent("RCPT TO:\r\n"); + + $this->assertEquals(0, $this->monitor->getBytesOut()); + $this->monitor->commandSent($evt); + $this->assertEquals(23, $this->monitor->getBytesOut()); + $this->monitor->commandSent($evt); + $this->assertEquals(46, $this->monitor->getBytesOut()); + } + + public function testBytesInIncreasesWhenResponsesReceived() + { + $evt = $this->createResponseEvent("250 Ok\r\n"); + + $this->assertEquals(0, $this->monitor->getBytesIn()); + $this->monitor->responseReceived($evt); + $this->assertEquals(8, $this->monitor->getBytesIn()); + $this->monitor->responseReceived($evt); + $this->assertEquals(16, $this->monitor->getBytesIn()); + } + + public function testCountersCanBeReset() + { + $evt = $this->createResponseEvent("250 Ok\r\n"); + + $this->assertEquals(0, $this->monitor->getBytesIn()); + $this->monitor->responseReceived($evt); + $this->assertEquals(8, $this->monitor->getBytesIn()); + $this->monitor->responseReceived($evt); + $this->assertEquals(16, $this->monitor->getBytesIn()); + + $evt = $this->createCommandEvent("RCPT TO:\r\n"); + + $this->assertEquals(0, $this->monitor->getBytesOut()); + $this->monitor->commandSent($evt); + $this->assertEquals(23, $this->monitor->getBytesOut()); + $this->monitor->commandSent($evt); + $this->assertEquals(46, $this->monitor->getBytesOut()); + + $this->monitor->reset(); + + $this->assertEquals(0, $this->monitor->getBytesOut()); + $this->assertEquals(0, $this->monitor->getBytesIn()); + } + + public function testBytesOutIncreasesAccordingToMessageLength() + { + $message = $this->createMessageWithByteCount(6); + $evt = $this->createSendEvent($message); + + $this->assertEquals(0, $this->monitor->getBytesOut()); + $this->monitor->sendPerformed($evt); + $this->assertEquals(6, $this->monitor->getBytesOut()); + $this->monitor->sendPerformed($evt); + $this->assertEquals(12, $this->monitor->getBytesOut()); + } + + private function createSendEvent($message) + { + $evt = $this->getMockBuilder('Swift_Events_SendEvent') + ->disableOriginalConstructor() + ->getMock(); + $evt->expects($this->any()) + ->method('getMessage') + ->will($this->returnValue($message)); + + return $evt; + } + + private function createCommandEvent($command) + { + $evt = $this->getMockBuilder('Swift_Events_CommandEvent') + ->disableOriginalConstructor() + ->getMock(); + $evt->expects($this->any()) + ->method('getCommand') + ->will($this->returnValue($command)); + + return $evt; + } + + private function createResponseEvent($response) + { + $evt = $this->getMockBuilder('Swift_Events_ResponseEvent') + ->disableOriginalConstructor() + ->getMock(); + $evt->expects($this->any()) + ->method('getResponse') + ->will($this->returnValue($response)); + + return $evt; + } + + private function createMessageWithByteCount($bytes) + { + $this->bytes = $bytes; + $msg = $this->getMockBuilder('Swift_Mime_SimpleMessage')->disableOriginalConstructor()->getMock(); + $msg->expects($this->any()) + ->method('toByteStream') + ->will($this->returnCallback(array($this, 'write'))); + /* $this->checking(Expectations::create() + -> ignoring($msg)->toByteStream(any()) -> calls(array($this, 'write')) + ); */ + + return $msg; + } + + public function write($is) + { + for ($i = 0; $i < $this->bytes; ++$i) { + $is->write('x'); + } + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/DecoratorPluginTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/DecoratorPluginTest.php new file mode 100644 index 00000000..2916e6c0 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/DecoratorPluginTest.php @@ -0,0 +1,284 @@ +createMessage( + $this->createHeaders(), + array('zip@button.tld' => 'Zipathon'), + array('chris.corbyn@swiftmailer.org' => 'Chris'), + 'Subject', + 'Hello {name}, you are customer #{id}' + ); + $message->shouldReceive('setBody') + ->once() + ->with('Hello Zip, you are customer #456'); + $message->shouldReceive('setBody') + ->zeroOrMoreTimes(); + + $plugin = $this->createPlugin( + array('zip@button.tld' => array('{name}' => 'Zip', '{id}' => '456')) + ); + + $evt = $this->createSendEvent($message); + + $plugin->beforeSendPerformed($evt); + $plugin->sendPerformed($evt); + } + + public function testReplacementsCanBeAppliedToSameMessageMultipleTimes() + { + $message = $this->createMessage( + $this->createHeaders(), + array('zip@button.tld' => 'Zipathon', 'foo@bar.tld' => 'Foo'), + array('chris.corbyn@swiftmailer.org' => 'Chris'), + 'Subject', + 'Hello {name}, you are customer #{id}' + ); + $message->shouldReceive('setBody') + ->once() + ->with('Hello Zip, you are customer #456'); + $message->shouldReceive('setBody') + ->once() + ->with('Hello {name}, you are customer #{id}'); + $message->shouldReceive('setBody') + ->once() + ->with('Hello Foo, you are customer #123'); + $message->shouldReceive('setBody') + ->zeroOrMoreTimes(); + + $plugin = $this->createPlugin( + array( + 'foo@bar.tld' => array('{name}' => 'Foo', '{id}' => '123'), + 'zip@button.tld' => array('{name}' => 'Zip', '{id}' => '456'), + ) + ); + + $evt = $this->createSendEvent($message); + + $plugin->beforeSendPerformed($evt); + $plugin->sendPerformed($evt); + $plugin->beforeSendPerformed($evt); + $plugin->sendPerformed($evt); + } + + public function testReplacementsCanBeMadeInHeaders() + { + $headers = $this->createHeaders(array( + $returnPathHeader = $this->createHeader('Return-Path', 'foo-{id}@swiftmailer.org'), + $toHeader = $this->createHeader('Subject', 'A message for {name}!'), + )); + + $message = $this->createMessage( + $headers, + array('zip@button.tld' => 'Zipathon'), + array('chris.corbyn@swiftmailer.org' => 'Chris'), + 'A message for {name}!', + 'Hello {name}, you are customer #{id}' + ); + + $message->shouldReceive('setBody') + ->once() + ->with('Hello Zip, you are customer #456'); + $toHeader->shouldReceive('setFieldBodyModel') + ->once() + ->with('A message for Zip!'); + $returnPathHeader->shouldReceive('setFieldBodyModel') + ->once() + ->with('foo-456@swiftmailer.org'); + $message->shouldReceive('setBody') + ->zeroOrMoreTimes(); + $toHeader->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes(); + $returnPathHeader->shouldReceive('setFieldBodyModel') + ->zeroOrMoreTimes(); + + $plugin = $this->createPlugin( + array('zip@button.tld' => array('{name}' => 'Zip', '{id}' => '456')) + ); + $evt = $this->createSendEvent($message); + + $plugin->beforeSendPerformed($evt); + $plugin->sendPerformed($evt); + } + + public function testReplacementsAreMadeOnSubparts() + { + $part1 = $this->createPart('text/plain', 'Your name is {name}?', '1@x'); + $part2 = $this->createPart('text/html', 'Your name is {name}?', '2@x'); + $message = $this->createMessage( + $this->createHeaders(), + array('zip@button.tld' => 'Zipathon'), + array('chris.corbyn@swiftmailer.org' => 'Chris'), + 'A message for {name}!', + 'Subject' + ); + $message->shouldReceive('getChildren') + ->zeroOrMoreTimes() + ->andReturn(array($part1, $part2)); + $part1->shouldReceive('setBody') + ->once() + ->with('Your name is Zip?'); + $part2->shouldReceive('setBody') + ->once() + ->with('Your name is Zip?'); + $part1->shouldReceive('setBody') + ->zeroOrMoreTimes(); + $part2->shouldReceive('setBody') + ->zeroOrMoreTimes(); + + $plugin = $this->createPlugin( + array('zip@button.tld' => array('{name}' => 'Zip', '{id}' => '456')) + ); + + $evt = $this->createSendEvent($message); + + $plugin->beforeSendPerformed($evt); + $plugin->sendPerformed($evt); + } + + public function testReplacementsCanBeTakenFromCustomReplacementsObject() + { + $message = $this->createMessage( + $this->createHeaders(), + array('foo@bar' => 'Foobar', 'zip@zap' => 'Zip zap'), + array('chris.corbyn@swiftmailer.org' => 'Chris'), + 'Subject', + 'Something {a}' + ); + + $replacements = $this->createReplacements(); + + $message->shouldReceive('setBody') + ->once() + ->with('Something b'); + $message->shouldReceive('setBody') + ->once() + ->with('Something c'); + $message->shouldReceive('setBody') + ->zeroOrMoreTimes(); + $replacements->shouldReceive('getReplacementsFor') + ->once() + ->with('foo@bar') + ->andReturn(array('{a}' => 'b')); + $replacements->shouldReceive('getReplacementsFor') + ->once() + ->with('zip@zap') + ->andReturn(array('{a}' => 'c')); + + $plugin = $this->createPlugin($replacements); + + $evt = $this->createSendEvent($message); + + $plugin->beforeSendPerformed($evt); + $plugin->sendPerformed($evt); + $plugin->beforeSendPerformed($evt); + $plugin->sendPerformed($evt); + } + + public function testReplacementsWithAMessageWithImmutableDate() + { + $message = (new Swift_Message('subject foo')) + ->setBody('body foo') + ->addTo('somebody@hostname.tld') + ->addFrom('somebody@hostname.tld'); + + $evt = $this->createSendEvent($message); + + $plugin = $this->createPlugin(array('somebody@hostname.tld' => array('foo' => 'bar'))); + + $plugin->beforeSendPerformed($evt); + + $this->assertEquals('subject bar', $message->getSubject()); + $this->assertEquals('body bar', $message->getBody()); + } + + private function createMessage($headers, $to = array(), $from = null, $subject = null, + $body = null) + { + $message = $this->getMockery('Swift_Mime_SimpleMessage')->shouldIgnoreMissing(); + foreach ($to as $addr => $name) { + $message->shouldReceive('getTo') + ->once() + ->andReturn(array($addr => $name)); + } + $message->shouldReceive('getHeaders') + ->zeroOrMoreTimes() + ->andReturn($headers); + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn($from); + $message->shouldReceive('getSubject') + ->zeroOrMoreTimes() + ->andReturn($subject); + $message->shouldReceive('getBody') + ->zeroOrMoreTimes() + ->andReturn($body); + + return $message; + } + + private function createPlugin($replacements) + { + return new Swift_Plugins_DecoratorPlugin($replacements); + } + + private function createReplacements() + { + return $this->getMockery('Swift_Plugins_Decorator_Replacements')->shouldIgnoreMissing(); + } + + private function createSendEvent(Swift_Mime_SimpleMessage $message) + { + $evt = $this->getMockery('Swift_Events_SendEvent')->shouldIgnoreMissing(); + $evt->shouldReceive('getMessage') + ->zeroOrMoreTimes() + ->andReturn($message); + + return $evt; + } + + private function createPart($type, $body, $id) + { + $part = $this->getMockery('Swift_Mime_SimpleMimeEntity')->shouldIgnoreMissing(); + $part->shouldReceive('getContentType') + ->zeroOrMoreTimes() + ->andReturn($type); + $part->shouldReceive('getBody') + ->zeroOrMoreTimes() + ->andReturn($body); + $part->shouldReceive('getId') + ->zeroOrMoreTimes() + ->andReturn($id); + + return $part; + } + + private function createHeaders($headers = array()) + { + $set = $this->getMockery('Swift_Mime_SimpleHeaderSet')->shouldIgnoreMissing(); + $set->shouldReceive('getAll') + ->zeroOrMoreTimes() + ->andReturn($headers); + + foreach ($headers as $header) { + $set->set($header); + } + + return $set; + } + + private function createHeader($name, $body = '') + { + $header = $this->getMockery('Swift_Mime_Header')->shouldIgnoreMissing(); + $header->shouldReceive('getFieldName') + ->zeroOrMoreTimes() + ->andReturn($name); + $header->shouldReceive('getFieldBodyModel') + ->zeroOrMoreTimes() + ->andReturn($body); + + return $header; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/LoggerPluginTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/LoggerPluginTest.php new file mode 100644 index 00000000..d66021cb --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/LoggerPluginTest.php @@ -0,0 +1,188 @@ +createLogger(); + $logger->expects($this->once()) + ->method('add') + ->with('foo'); + + $plugin = $this->createPlugin($logger); + $plugin->add('foo'); + } + + public function testLoggerDelegatesDumpingEntries() + { + $logger = $this->createLogger(); + $logger->expects($this->once()) + ->method('dump') + ->will($this->returnValue('foobar')); + + $plugin = $this->createPlugin($logger); + $this->assertEquals('foobar', $plugin->dump()); + } + + public function testLoggerDelegatesClearingEntries() + { + $logger = $this->createLogger(); + $logger->expects($this->once()) + ->method('clear'); + + $plugin = $this->createPlugin($logger); + $plugin->clear(); + } + + public function testCommandIsSentToLogger() + { + $evt = $this->createCommandEvent("foo\r\n"); + $logger = $this->createLogger(); + $logger->expects($this->once()) + ->method('add') + ->with(static::regExp('~foo\r\n~')); + + $plugin = $this->createPlugin($logger); + $plugin->commandSent($evt); + } + + public function testResponseIsSentToLogger() + { + $evt = $this->createResponseEvent("354 Go ahead\r\n"); + $logger = $this->createLogger(); + $logger->expects($this->once()) + ->method('add') + ->with(static::regExp('~354 Go ahead\r\n~')); + + $plugin = $this->createPlugin($logger); + $plugin->responseReceived($evt); + } + + public function testTransportBeforeStartChangeIsSentToLogger() + { + $evt = $this->createTransportChangeEvent(); + $logger = $this->createLogger(); + $logger->expects($this->once()) + ->method('add') + ->with($this->anything()); + + $plugin = $this->createPlugin($logger); + $plugin->beforeTransportStarted($evt); + } + + public function testTransportStartChangeIsSentToLogger() + { + $evt = $this->createTransportChangeEvent(); + $logger = $this->createLogger(); + $logger->expects($this->once()) + ->method('add') + ->with($this->anything()); + + $plugin = $this->createPlugin($logger); + $plugin->transportStarted($evt); + } + + public function testTransportStopChangeIsSentToLogger() + { + $evt = $this->createTransportChangeEvent(); + $logger = $this->createLogger(); + $logger->expects($this->once()) + ->method('add') + ->with($this->anything()); + + $plugin = $this->createPlugin($logger); + $plugin->transportStopped($evt); + } + + public function testTransportBeforeStopChangeIsSentToLogger() + { + $evt = $this->createTransportChangeEvent(); + $logger = $this->createLogger(); + $logger->expects($this->once()) + ->method('add') + ->with($this->anything()); + + $plugin = $this->createPlugin($logger); + $plugin->beforeTransportStopped($evt); + } + + public function testExceptionsArePassedToDelegateAndLeftToBubbleUp() + { + $transport = $this->createTransport(); + $evt = $this->createTransportExceptionEvent(); + $logger = $this->createLogger(); + $logger->expects($this->once()) + ->method('add') + ->with($this->anything()); + + $plugin = $this->createPlugin($logger); + try { + $plugin->exceptionThrown($evt); + $this->fail('Exception should bubble up.'); + } catch (Swift_TransportException $ex) { + } + } + + private function createLogger() + { + return $this->getMockBuilder('Swift_Plugins_Logger')->getMock(); + } + + private function createPlugin($logger) + { + return new Swift_Plugins_LoggerPlugin($logger); + } + + private function createCommandEvent($command) + { + $evt = $this->getMockBuilder('Swift_Events_CommandEvent') + ->disableOriginalConstructor() + ->getMock(); + $evt->expects($this->any()) + ->method('getCommand') + ->will($this->returnValue($command)); + + return $evt; + } + + private function createResponseEvent($response) + { + $evt = $this->getMockBuilder('Swift_Events_ResponseEvent') + ->disableOriginalConstructor() + ->getMock(); + $evt->expects($this->any()) + ->method('getResponse') + ->will($this->returnValue($response)); + + return $evt; + } + + private function createTransport() + { + return $this->getMockBuilder('Swift_Transport')->getMock(); + } + + private function createTransportChangeEvent() + { + $evt = $this->getMockBuilder('Swift_Events_TransportChangeEvent') + ->disableOriginalConstructor() + ->getMock(); + $evt->expects($this->any()) + ->method('getSource') + ->will($this->returnValue($this->createTransport())); + + return $evt; + } + + public function createTransportExceptionEvent() + { + $evt = $this->getMockBuilder('Swift_Events_TransportExceptionEvent') + ->disableOriginalConstructor() + ->getMock(); + $evt->expects($this->any()) + ->method('getException') + ->will($this->returnValue(new Swift_TransportException(''))); + + return $evt; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Loggers/ArrayLoggerTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Loggers/ArrayLoggerTest.php new file mode 100644 index 00000000..48c1b075 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Loggers/ArrayLoggerTest.php @@ -0,0 +1,65 @@ +add(">> Foo\r\n"); + $this->assertEquals(">> Foo\r\n", $logger->dump()); + } + + public function testAddingMultipleEntriesDumpsMultipleLines() + { + $logger = new Swift_Plugins_Loggers_ArrayLogger(); + $logger->add(">> FOO\r\n"); + $logger->add("<< 502 That makes no sense\r\n"); + $logger->add(">> RSET\r\n"); + $logger->add("<< 250 OK\r\n"); + + $this->assertEquals( + ">> FOO\r\n".PHP_EOL. + "<< 502 That makes no sense\r\n".PHP_EOL. + ">> RSET\r\n".PHP_EOL. + "<< 250 OK\r\n", + $logger->dump() + ); + } + + public function testLogCanBeCleared() + { + $logger = new Swift_Plugins_Loggers_ArrayLogger(); + $logger->add(">> FOO\r\n"); + $logger->add("<< 502 That makes no sense\r\n"); + $logger->add(">> RSET\r\n"); + $logger->add("<< 250 OK\r\n"); + + $this->assertEquals( + ">> FOO\r\n".PHP_EOL. + "<< 502 That makes no sense\r\n".PHP_EOL. + ">> RSET\r\n".PHP_EOL. + "<< 250 OK\r\n", + $logger->dump() + ); + + $logger->clear(); + + $this->assertEquals('', $logger->dump()); + } + + public function testLengthCanBeTruncated() + { + $logger = new Swift_Plugins_Loggers_ArrayLogger(2); + $logger->add(">> FOO\r\n"); + $logger->add("<< 502 That makes no sense\r\n"); + $logger->add(">> RSET\r\n"); + $logger->add("<< 250 OK\r\n"); + + $this->assertEquals( + ">> RSET\r\n".PHP_EOL. + "<< 250 OK\r\n", + $logger->dump(), + '%s: Log should be truncated to last 2 entries' + ); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Loggers/EchoLoggerTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Loggers/EchoLoggerTest.php new file mode 100644 index 00000000..c43660da --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Loggers/EchoLoggerTest.php @@ -0,0 +1,24 @@ +add('>> Foo'); + $data = ob_get_clean(); + + $this->assertEquals('>> Foo'.PHP_EOL, $data); + } + + public function testAddingEntryDumpsEscapedLineWithHtml() + { + $logger = new Swift_Plugins_Loggers_EchoLogger(true); + ob_start(); + $logger->add('>> Foo'); + $data = ob_get_clean(); + + $this->assertEquals('>> Foo
'.PHP_EOL, $data); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/PopBeforeSmtpPluginTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/PopBeforeSmtpPluginTest.php new file mode 100644 index 00000000..cf88a4e7 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/PopBeforeSmtpPluginTest.php @@ -0,0 +1,101 @@ +createConnection(); + $connection->expects($this->once()) + ->method('connect'); + + $plugin = $this->createPlugin('pop.host.tld', 110); + $plugin->setConnection($connection); + + $transport = $this->createTransport(); + $evt = $this->createTransportChangeEvent($transport); + + $plugin->beforeTransportStarted($evt); + } + + public function testPluginDisconnectsFromPop3HostBeforeTransportStarts() + { + $connection = $this->createConnection(); + $connection->expects($this->once()) + ->method('disconnect'); + + $plugin = $this->createPlugin('pop.host.tld', 110); + $plugin->setConnection($connection); + + $transport = $this->createTransport(); + $evt = $this->createTransportChangeEvent($transport); + + $plugin->beforeTransportStarted($evt); + } + + public function testPluginDoesNotConnectToSmtpIfBoundToDifferentTransport() + { + $connection = $this->createConnection(); + $connection->expects($this->never()) + ->method('disconnect'); + $connection->expects($this->never()) + ->method('connect'); + + $smtp = $this->createTransport(); + + $plugin = $this->createPlugin('pop.host.tld', 110); + $plugin->setConnection($connection); + $plugin->bindSmtp($smtp); + + $transport = $this->createTransport(); + $evt = $this->createTransportChangeEvent($transport); + + $plugin->beforeTransportStarted($evt); + } + + public function testPluginCanBindToSpecificTransport() + { + $connection = $this->createConnection(); + $connection->expects($this->once()) + ->method('connect'); + + $smtp = $this->createTransport(); + + $plugin = $this->createPlugin('pop.host.tld', 110); + $plugin->setConnection($connection); + $plugin->bindSmtp($smtp); + + $evt = $this->createTransportChangeEvent($smtp); + + $plugin->beforeTransportStarted($evt); + } + + private function createTransport() + { + return $this->getMockBuilder('Swift_Transport')->getMock(); + } + + private function createTransportChangeEvent($transport) + { + $evt = $this->getMockBuilder('Swift_Events_TransportChangeEvent') + ->disableOriginalConstructor() + ->getMock(); + $evt->expects($this->any()) + ->method('getSource') + ->will($this->returnValue($transport)); + $evt->expects($this->any()) + ->method('getTransport') + ->will($this->returnValue($transport)); + + return $evt; + } + + public function createConnection() + { + return $this->getMockBuilder('Swift_Plugins_Pop_Pop3Connection')->getMock(); + } + + public function createPlugin($host, $port, $crypto = null) + { + return new Swift_Plugins_PopBeforeSmtpPlugin($host, $port, $crypto); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/RedirectingPluginTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/RedirectingPluginTest.php new file mode 100644 index 00000000..050c7eb2 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/RedirectingPluginTest.php @@ -0,0 +1,183 @@ +assertEquals('fabien@example.com', $plugin->getRecipient()); + $plugin->setRecipient('chris@example.com'); + $this->assertEquals('chris@example.com', $plugin->getRecipient()); + } + + public function testPluginChangesRecipients() + { + $message = (new Swift_Message()) + ->setSubject('...') + ->setFrom(array('john@example.com' => 'John Doe')) + ->setTo($to = array( + 'fabien-to@example.com' => 'Fabien (To)', + 'chris-to@example.com' => 'Chris (To)', + )) + ->setCc($cc = array( + 'fabien-cc@example.com' => 'Fabien (Cc)', + 'chris-cc@example.com' => 'Chris (Cc)', + )) + ->setBcc($bcc = array( + 'fabien-bcc@example.com' => 'Fabien (Bcc)', + 'chris-bcc@example.com' => 'Chris (Bcc)', + )) + ->setBody('...') + ; + + $plugin = new Swift_Plugins_RedirectingPlugin('god@example.com'); + + $evt = $this->createSendEvent($message); + + $plugin->beforeSendPerformed($evt); + + $this->assertEquals($message->getTo(), array('god@example.com' => '')); + $this->assertEquals($message->getCc(), array()); + $this->assertEquals($message->getBcc(), array()); + + $plugin->sendPerformed($evt); + + $this->assertEquals($message->getTo(), $to); + $this->assertEquals($message->getCc(), $cc); + $this->assertEquals($message->getBcc(), $bcc); + } + + public function testPluginRespectsUnsetToList() + { + $message = (new Swift_Message()) + ->setSubject('...') + ->setFrom(array('john@example.com' => 'John Doe')) + ->setCc($cc = array( + 'fabien-cc@example.com' => 'Fabien (Cc)', + 'chris-cc@example.com' => 'Chris (Cc)', + )) + ->setBcc($bcc = array( + 'fabien-bcc@example.com' => 'Fabien (Bcc)', + 'chris-bcc@example.com' => 'Chris (Bcc)', + )) + ->setBody('...') + ; + + $plugin = new Swift_Plugins_RedirectingPlugin('god@example.com'); + + $evt = $this->createSendEvent($message); + + $plugin->beforeSendPerformed($evt); + + $this->assertEquals($message->getTo(), array('god@example.com' => '')); + $this->assertEquals($message->getCc(), array()); + $this->assertEquals($message->getBcc(), array()); + + $plugin->sendPerformed($evt); + + $this->assertEquals($message->getTo(), array()); + $this->assertEquals($message->getCc(), $cc); + $this->assertEquals($message->getBcc(), $bcc); + } + + public function testPluginRespectsAWhitelistOfPatterns() + { + $message = (new Swift_Message()) + ->setSubject('...') + ->setFrom(array('john@example.com' => 'John Doe')) + ->setTo($to = array( + 'fabien-to@example.com' => 'Fabien (To)', + 'chris-to@example.com' => 'Chris (To)', + 'lars-to@internal.com' => 'Lars (To)', + )) + ->setCc($cc = array( + 'fabien-cc@example.com' => 'Fabien (Cc)', + 'chris-cc@example.com' => 'Chris (Cc)', + 'lars-cc@internal.org' => 'Lars (Cc)', + )) + ->setBcc($bcc = array( + 'fabien-bcc@example.com' => 'Fabien (Bcc)', + 'chris-bcc@example.com' => 'Chris (Bcc)', + 'john-bcc@example.org' => 'John (Bcc)', + )) + ->setBody('...') + ; + + $recipient = 'god@example.com'; + $patterns = array('/^.*@internal.[a-z]+$/', '/^john-.*$/'); + + $plugin = new Swift_Plugins_RedirectingPlugin($recipient, $patterns); + + $this->assertEquals($recipient, $plugin->getRecipient()); + $this->assertEquals($plugin->getWhitelist(), $patterns); + + $evt = $this->createSendEvent($message); + + $plugin->beforeSendPerformed($evt); + + $this->assertEquals($message->getTo(), array('lars-to@internal.com' => 'Lars (To)', 'god@example.com' => null)); + $this->assertEquals($message->getCc(), array('lars-cc@internal.org' => 'Lars (Cc)')); + $this->assertEquals($message->getBcc(), array('john-bcc@example.org' => 'John (Bcc)')); + + $plugin->sendPerformed($evt); + + $this->assertEquals($message->getTo(), $to); + $this->assertEquals($message->getCc(), $cc); + $this->assertEquals($message->getBcc(), $bcc); + } + + public function testArrayOfRecipientsCanBeExplicitlyDefined() + { + $message = (new Swift_Message()) + ->setSubject('...') + ->setFrom(array('john@example.com' => 'John Doe')) + ->setTo(array( + 'fabien@example.com' => 'Fabien', + 'chris@example.com' => 'Chris (To)', + 'lars-to@internal.com' => 'Lars (To)', + )) + ->setCc(array( + 'fabien@example.com' => 'Fabien', + 'chris-cc@example.com' => 'Chris (Cc)', + 'lars-cc@internal.org' => 'Lars (Cc)', + )) + ->setBcc(array( + 'fabien@example.com' => 'Fabien', + 'chris-bcc@example.com' => 'Chris (Bcc)', + 'john-bcc@example.org' => 'John (Bcc)', + )) + ->setBody('...') + ; + + $recipients = array('god@example.com', 'fabien@example.com'); + $patterns = array('/^.*@internal.[a-z]+$/'); + + $plugin = new Swift_Plugins_RedirectingPlugin($recipients, $patterns); + + $evt = $this->createSendEvent($message); + + $plugin->beforeSendPerformed($evt); + + $this->assertEquals( + $message->getTo(), + array('fabien@example.com' => 'Fabien', 'lars-to@internal.com' => 'Lars (To)', 'god@example.com' => null) + ); + $this->assertEquals( + $message->getCc(), + array('fabien@example.com' => 'Fabien', 'lars-cc@internal.org' => 'Lars (Cc)') + ); + $this->assertEquals($message->getBcc(), array('fabien@example.com' => 'Fabien')); + } + + private function createSendEvent(Swift_Mime_SimpleMessage $message) + { + $evt = $this->getMockBuilder('Swift_Events_SendEvent') + ->disableOriginalConstructor() + ->getMock(); + $evt->expects($this->any()) + ->method('getMessage') + ->will($this->returnValue($message)); + + return $evt; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/ReporterPluginTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/ReporterPluginTest.php new file mode 100644 index 00000000..f5ff7f86 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/ReporterPluginTest.php @@ -0,0 +1,86 @@ +createMessage(); + $evt = $this->createSendEvent(); + $reporter = $this->createReporter(); + + $message->shouldReceive('getTo')->zeroOrMoreTimes()->andReturn(array('foo@bar.tld' => 'Foo')); + $evt->shouldReceive('getMessage')->zeroOrMoreTimes()->andReturn($message); + $evt->shouldReceive('getFailedRecipients')->zeroOrMoreTimes()->andReturn(array()); + $reporter->shouldReceive('notify')->once()->with($message, 'foo@bar.tld', Swift_Plugins_Reporter::RESULT_PASS); + + $plugin = new Swift_Plugins_ReporterPlugin($reporter); + $plugin->sendPerformed($evt); + } + + public function testReportingFailedTo() + { + $message = $this->createMessage(); + $evt = $this->createSendEvent(); + $reporter = $this->createReporter(); + + $message->shouldReceive('getTo')->zeroOrMoreTimes()->andReturn(array('foo@bar.tld' => 'Foo', 'zip@button' => 'Zip')); + $evt->shouldReceive('getMessage')->zeroOrMoreTimes()->andReturn($message); + $evt->shouldReceive('getFailedRecipients')->zeroOrMoreTimes()->andReturn(array('zip@button')); + $reporter->shouldReceive('notify')->once()->with($message, 'foo@bar.tld', Swift_Plugins_Reporter::RESULT_PASS); + $reporter->shouldReceive('notify')->once()->with($message, 'zip@button', Swift_Plugins_Reporter::RESULT_FAIL); + + $plugin = new Swift_Plugins_ReporterPlugin($reporter); + $plugin->sendPerformed($evt); + } + + public function testReportingFailedCc() + { + $message = $this->createMessage(); + $evt = $this->createSendEvent(); + $reporter = $this->createReporter(); + + $message->shouldReceive('getTo')->zeroOrMoreTimes()->andReturn(array('foo@bar.tld' => 'Foo')); + $message->shouldReceive('getCc')->zeroOrMoreTimes()->andReturn(array('zip@button' => 'Zip', 'test@test.com' => 'Test')); + $evt->shouldReceive('getMessage')->zeroOrMoreTimes()->andReturn($message); + $evt->shouldReceive('getFailedRecipients')->zeroOrMoreTimes()->andReturn(array('zip@button')); + $reporter->shouldReceive('notify')->once()->with($message, 'foo@bar.tld', Swift_Plugins_Reporter::RESULT_PASS); + $reporter->shouldReceive('notify')->once()->with($message, 'zip@button', Swift_Plugins_Reporter::RESULT_FAIL); + $reporter->shouldReceive('notify')->once()->with($message, 'test@test.com', Swift_Plugins_Reporter::RESULT_PASS); + + $plugin = new Swift_Plugins_ReporterPlugin($reporter); + $plugin->sendPerformed($evt); + } + + public function testReportingFailedBcc() + { + $message = $this->createMessage(); + $evt = $this->createSendEvent(); + $reporter = $this->createReporter(); + + $message->shouldReceive('getTo')->zeroOrMoreTimes()->andReturn(array('foo@bar.tld' => 'Foo')); + $message->shouldReceive('getBcc')->zeroOrMoreTimes()->andReturn(array('zip@button' => 'Zip', 'test@test.com' => 'Test')); + $evt->shouldReceive('getMessage')->zeroOrMoreTimes()->andReturn($message); + $evt->shouldReceive('getFailedRecipients')->zeroOrMoreTimes()->andReturn(array('zip@button')); + $reporter->shouldReceive('notify')->once()->with($message, 'foo@bar.tld', Swift_Plugins_Reporter::RESULT_PASS); + $reporter->shouldReceive('notify')->once()->with($message, 'zip@button', Swift_Plugins_Reporter::RESULT_FAIL); + $reporter->shouldReceive('notify')->once()->with($message, 'test@test.com', Swift_Plugins_Reporter::RESULT_PASS); + + $plugin = new Swift_Plugins_ReporterPlugin($reporter); + $plugin->sendPerformed($evt); + } + + private function createMessage() + { + return $this->getMockery('Swift_Mime_SimpleMessage')->shouldIgnoreMissing(); + } + + private function createSendEvent() + { + return $this->getMockery('Swift_Events_SendEvent')->shouldIgnoreMissing(); + } + + private function createReporter() + { + return $this->getMockery('Swift_Plugins_Reporter')->shouldIgnoreMissing(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Reporters/HitReporterTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Reporters/HitReporterTest.php new file mode 100644 index 00000000..70a46710 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Reporters/HitReporterTest.php @@ -0,0 +1,64 @@ +hitReporter = new Swift_Plugins_Reporters_HitReporter(); + $this->message = $this->getMockBuilder('Swift_Mime_SimpleMessage')->disableOriginalConstructor()->getMock(); + } + + public function testReportingFail() + { + $this->hitReporter->notify($this->message, 'foo@bar.tld', + Swift_Plugins_Reporter::RESULT_FAIL + ); + $this->assertEquals(array('foo@bar.tld'), + $this->hitReporter->getFailedRecipients() + ); + } + + public function testMultipleReports() + { + $this->hitReporter->notify($this->message, 'foo@bar.tld', + Swift_Plugins_Reporter::RESULT_FAIL + ); + $this->hitReporter->notify($this->message, 'zip@button', + Swift_Plugins_Reporter::RESULT_FAIL + ); + $this->assertEquals(array('foo@bar.tld', 'zip@button'), + $this->hitReporter->getFailedRecipients() + ); + } + + public function testReportingPassIsIgnored() + { + $this->hitReporter->notify($this->message, 'foo@bar.tld', + Swift_Plugins_Reporter::RESULT_FAIL + ); + $this->hitReporter->notify($this->message, 'zip@button', + Swift_Plugins_Reporter::RESULT_PASS + ); + $this->assertEquals(array('foo@bar.tld'), + $this->hitReporter->getFailedRecipients() + ); + } + + public function testBufferCanBeCleared() + { + $this->hitReporter->notify($this->message, 'foo@bar.tld', + Swift_Plugins_Reporter::RESULT_FAIL + ); + $this->hitReporter->notify($this->message, 'zip@button', + Swift_Plugins_Reporter::RESULT_FAIL + ); + $this->assertEquals(array('foo@bar.tld', 'zip@button'), + $this->hitReporter->getFailedRecipients() + ); + $this->hitReporter->clear(); + $this->assertEquals(array(), $this->hitReporter->getFailedRecipients()); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Reporters/HtmlReporterTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Reporters/HtmlReporterTest.php new file mode 100644 index 00000000..6b86cfe2 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/Reporters/HtmlReporterTest.php @@ -0,0 +1,54 @@ +html = new Swift_Plugins_Reporters_HtmlReporter(); + $this->message = $this->getMockBuilder('Swift_Mime_SimpleMessage')->disableOriginalConstructor()->getMock(); + } + + public function testReportingPass() + { + ob_start(); + $this->html->notify($this->message, 'foo@bar.tld', + Swift_Plugins_Reporter::RESULT_PASS + ); + $html = ob_get_clean(); + + $this->assertRegExp('~ok|pass~i', $html, '%s: Reporter should indicate pass'); + $this->assertRegExp('~foo@bar\.tld~', $html, '%s: Reporter should show address'); + } + + public function testReportingFail() + { + ob_start(); + $this->html->notify($this->message, 'zip@button', + Swift_Plugins_Reporter::RESULT_FAIL + ); + $html = ob_get_clean(); + + $this->assertRegExp('~fail~i', $html, '%s: Reporter should indicate fail'); + $this->assertRegExp('~zip@button~', $html, '%s: Reporter should show address'); + } + + public function testMultipleReports() + { + ob_start(); + $this->html->notify($this->message, 'foo@bar.tld', + Swift_Plugins_Reporter::RESULT_PASS + ); + $this->html->notify($this->message, 'zip@button', + Swift_Plugins_Reporter::RESULT_FAIL + ); + $html = ob_get_clean(); + + $this->assertRegExp('~ok|pass~i', $html, '%s: Reporter should indicate pass'); + $this->assertRegExp('~foo@bar\.tld~', $html, '%s: Reporter should show address'); + $this->assertRegExp('~fail~i', $html, '%s: Reporter should indicate fail'); + $this->assertRegExp('~zip@button~', $html, '%s: Reporter should show address'); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/ThrottlerPluginTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/ThrottlerPluginTest.php new file mode 100644 index 00000000..e35dcc8d --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Plugins/ThrottlerPluginTest.php @@ -0,0 +1,102 @@ +createSleeper(); + $timer = $this->createTimer(); + + //10MB/min + $plugin = new Swift_Plugins_ThrottlerPlugin( + 10000000, Swift_Plugins_ThrottlerPlugin::BYTES_PER_MINUTE, + $sleeper, $timer + ); + + $timer->shouldReceive('getTimestamp')->once()->andReturn(0); + $timer->shouldReceive('getTimestamp')->once()->andReturn(1); //expected 0.6 + $timer->shouldReceive('getTimestamp')->once()->andReturn(1); //expected 1.2 (sleep 1) + $timer->shouldReceive('getTimestamp')->once()->andReturn(2); //expected 1.8 + $timer->shouldReceive('getTimestamp')->once()->andReturn(2); //expected 2.4 (sleep 1) + $sleeper->shouldReceive('sleep')->twice()->with(1); + + //10,000,000 bytes per minute + //100,000 bytes per email + + // .: (10,000,000/100,000)/60 emails per second = 1.667 emais/sec + + $message = $this->createMessageWithByteCount(100000); //100KB + + $evt = $this->createSendEvent($message); + + for ($i = 0; $i < 5; ++$i) { + $plugin->beforeSendPerformed($evt); + $plugin->sendPerformed($evt); + } + } + + public function testMessagesPerMinuteThrottling() + { + $sleeper = $this->createSleeper(); + $timer = $this->createTimer(); + + //60/min + $plugin = new Swift_Plugins_ThrottlerPlugin( + 60, Swift_Plugins_ThrottlerPlugin::MESSAGES_PER_MINUTE, + $sleeper, $timer + ); + + $timer->shouldReceive('getTimestamp')->once()->andReturn(0); + $timer->shouldReceive('getTimestamp')->once()->andReturn(0); //expected 1 (sleep 1) + $timer->shouldReceive('getTimestamp')->once()->andReturn(2); //expected 2 + $timer->shouldReceive('getTimestamp')->once()->andReturn(2); //expected 3 (sleep 1) + $timer->shouldReceive('getTimestamp')->once()->andReturn(4); //expected 4 + $sleeper->shouldReceive('sleep')->twice()->with(1); + + //60 messages per minute + //1 message per second + + $message = $this->createMessageWithByteCount(10); + + $evt = $this->createSendEvent($message); + + for ($i = 0; $i < 5; ++$i) { + $plugin->beforeSendPerformed($evt); + $plugin->sendPerformed($evt); + } + } + + private function createSleeper() + { + return $this->getMockery('Swift_Plugins_Sleeper'); + } + + private function createTimer() + { + return $this->getMockery('Swift_Plugins_Timer'); + } + + private function createMessageWithByteCount($bytes) + { + $msg = $this->getMockery('Swift_Mime_SimpleMessage'); + $msg->shouldReceive('toByteStream') + ->zeroOrMoreTimes() + ->andReturnUsing(function ($is) use ($bytes) { + for ($i = 0; $i < $bytes; ++$i) { + $is->write('x'); + } + }); + + return $msg; + } + + private function createSendEvent($message) + { + $evt = $this->getMockery('Swift_Events_SendEvent'); + $evt->shouldReceive('getMessage') + ->zeroOrMoreTimes() + ->andReturn($message); + + return $evt; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Signers/DKIMSignerTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Signers/DKIMSignerTest.php new file mode 100644 index 00000000..c1e0cac1 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Signers/DKIMSignerTest.php @@ -0,0 +1,220 @@ +createHeaders(); + $messageContent = 'Hello World'; + $signer = new Swift_Signers_DKIMSigner(file_get_contents(dirname(dirname(dirname(__DIR__))).'/_samples/dkim/dkim.test.priv'), 'dummy.nxdomain.be', 'dummySelector'); + /* @var $signer Swift_Signers_HeaderSigner */ + $altered = $signer->getAlteredHeaders(); + $signer->reset(); + // Headers + $signer->setHeaders($headers); + // Body + $signer->startBody(); + $signer->write($messageContent); + $signer->endBody(); + // Signing + $signer->addSignature($headers); + } + + // SHA1 Signing + public function testSigningSHA1() + { + $headerSet = $this->createHeaderSet(); + $messageContent = 'Hello World'; + $signer = new Swift_Signers_DKIMSigner(file_get_contents(dirname(dirname(dirname(__DIR__))).'/_samples/dkim/dkim.test.priv'), 'dummy.nxdomain.be', 'dummySelector'); + $signer->setHashAlgorithm('rsa-sha1'); + $signer->setSignatureTimestamp('1299879181'); + $altered = $signer->getAlteredHeaders(); + $this->assertEquals(array('DKIM-Signature'), $altered); + $signer->reset(); + $signer->setHeaders($headerSet); + $this->assertFalse($headerSet->has('DKIM-Signature')); + $signer->startBody(); + $signer->write($messageContent); + $signer->endBody(); + $signer->addSignature($headerSet); + $this->assertTrue($headerSet->has('DKIM-Signature')); + $dkim = $headerSet->getAll('DKIM-Signature'); + $sig = reset($dkim); + $this->assertEquals($sig->getValue(), 'v=1; a=rsa-sha1; bh=wlbYcY9O9OPInGJ4D0E/rGsvMLE=; d=dummy.nxdomain.be; h=; i=@dummy.nxdomain.be; s=dummySelector; t=1299879181; b=RMSNelzM2O5MAAnMjT3G3/VF36S3DGJXoPCXR001F1WDReu0prGphWjuzK/m6V1pwqQL8cCNg Hi74mTx2bvyAvmkjvQtJf1VMUOCc9WHGcm1Yec66I3ZWoNMGSWZ1EKAm2CtTzyG0IFw4ml9DI wSkyAFxlgicckDD6FibhqwX4w='); + } + + // SHA256 Signing + public function testSigning256() + { + $headerSet = $this->createHeaderSet(); + $messageContent = 'Hello World'; + $signer = new Swift_Signers_DKIMSigner(file_get_contents(dirname(dirname(dirname(__DIR__))).'/_samples/dkim/dkim.test.priv'), 'dummy.nxdomain.be', 'dummySelector'); + $signer->setHashAlgorithm('rsa-sha256'); + $signer->setSignatureTimestamp('1299879181'); + $altered = $signer->getAlteredHeaders(); + $this->assertEquals(array('DKIM-Signature'), $altered); + $signer->reset(); + $signer->setHeaders($headerSet); + $this->assertFalse($headerSet->has('DKIM-Signature')); + $signer->startBody(); + $signer->write($messageContent); + $signer->endBody(); + $signer->addSignature($headerSet); + $this->assertTrue($headerSet->has('DKIM-Signature')); + $dkim = $headerSet->getAll('DKIM-Signature'); + $sig = reset($dkim); + $this->assertEquals($sig->getValue(), 'v=1; a=rsa-sha256; bh=f+W+hu8dIhf2VAni89o8lF6WKTXi7nViA4RrMdpD5/U=; d=dummy.nxdomain.be; h=; i=@dummy.nxdomain.be; s=dummySelector; t=1299879181; b=jqPmieHzF5vR9F4mXCAkowuphpO4iJ8IAVuioh1BFZ3VITXZj5jlOFxULJMBiiApm2keJirnh u4mzogj444QkpT3lJg8/TBGAYQPdcvkG3KC0jdyN6QpSgpITBJG2BwWa+keXsv2bkQgLRAzNx qRhP45vpHCKun0Tg9LrwW/KCg='); + } + + // Relaxed/Relaxed Hash Signing + public function testSigningRelaxedRelaxed256() + { + $headerSet = $this->createHeaderSet(); + $messageContent = 'Hello World'; + $signer = new Swift_Signers_DKIMSigner(file_get_contents(dirname(dirname(dirname(__DIR__))).'/_samples/dkim/dkim.test.priv'), 'dummy.nxdomain.be', 'dummySelector'); + $signer->setHashAlgorithm('rsa-sha256'); + $signer->setSignatureTimestamp('1299879181'); + $signer->setBodyCanon('relaxed'); + $signer->setHeaderCanon('relaxed'); + $altered = $signer->getAlteredHeaders(); + $this->assertEquals(array('DKIM-Signature'), $altered); + $signer->reset(); + $signer->setHeaders($headerSet); + $this->assertFalse($headerSet->has('DKIM-Signature')); + $signer->startBody(); + $signer->write($messageContent); + $signer->endBody(); + $signer->addSignature($headerSet); + $this->assertTrue($headerSet->has('DKIM-Signature')); + $dkim = $headerSet->getAll('DKIM-Signature'); + $sig = reset($dkim); + $this->assertEquals($sig->getValue(), 'v=1; a=rsa-sha256; bh=f+W+hu8dIhf2VAni89o8lF6WKTXi7nViA4RrMdpD5/U=; d=dummy.nxdomain.be; h=; i=@dummy.nxdomain.be; s=dummySelector; c=relaxed/relaxed; t=1299879181; b=gzOI+PX6HpZKQFzwwmxzcVJsyirdLXOS+4pgfCpVHQIdqYusKLrhlLeFBTNoz75HrhNvGH6T0 Rt3w5aTqkrWfUuAEYt0Ns14GowLM7JojaFN+pZ4eYnRB3CBBgW6fee4NEMD5WPca3uS09tr1E 10RYh9ILlRtl+84sovhx5id3Y='); + } + + // Relaxed/Simple Hash Signing + public function testSigningRelaxedSimple256() + { + $headerSet = $this->createHeaderSet(); + $messageContent = 'Hello World'; + $signer = new Swift_Signers_DKIMSigner(file_get_contents(dirname(dirname(dirname(__DIR__))).'/_samples/dkim/dkim.test.priv'), 'dummy.nxdomain.be', 'dummySelector'); + $signer->setHashAlgorithm('rsa-sha256'); + $signer->setSignatureTimestamp('1299879181'); + $signer->setHeaderCanon('relaxed'); + $altered = $signer->getAlteredHeaders(); + $this->assertEquals(array('DKIM-Signature'), $altered); + $signer->reset(); + $signer->setHeaders($headerSet); + $this->assertFalse($headerSet->has('DKIM-Signature')); + $signer->startBody(); + $signer->write($messageContent); + $signer->endBody(); + $signer->addSignature($headerSet); + $this->assertTrue($headerSet->has('DKIM-Signature')); + $dkim = $headerSet->getAll('DKIM-Signature'); + $sig = reset($dkim); + $this->assertEquals($sig->getValue(), 'v=1; a=rsa-sha256; bh=f+W+hu8dIhf2VAni89o8lF6WKTXi7nViA4RrMdpD5/U=; d=dummy.nxdomain.be; h=; i=@dummy.nxdomain.be; s=dummySelector; c=relaxed; t=1299879181; b=dLPJNec5v81oelyzGOY0qPqTlGnQeNfUNBOrV/JKbStr3NqWGI9jH4JAe2YvO2V32lfPNoby1 4MMzZ6EPkaZkZDDSPa+53YbCPQAlqiD9QZZIUe2UNM33HN8yAMgiWEF5aP7MbQnxeVZMfVLEl 9S8qOImu+K5JZqhQQTL0dgLwA='); + } + + // Simple/Relaxed Hash Signing + public function testSigningSimpleRelaxed256() + { + $headerSet = $this->createHeaderSet(); + $messageContent = 'Hello World'; + $signer = new Swift_Signers_DKIMSigner(file_get_contents(dirname(dirname(dirname(__DIR__))).'/_samples/dkim/dkim.test.priv'), 'dummy.nxdomain.be', 'dummySelector'); + $signer->setHashAlgorithm('rsa-sha256'); + $signer->setSignatureTimestamp('1299879181'); + $signer->setBodyCanon('relaxed'); + $altered = $signer->getAlteredHeaders(); + $this->assertEquals(array('DKIM-Signature'), $altered); + $signer->reset(); + $signer->setHeaders($headerSet); + $this->assertFalse($headerSet->has('DKIM-Signature')); + $signer->startBody(); + $signer->write($messageContent); + $signer->endBody(); + $signer->addSignature($headerSet); + $this->assertTrue($headerSet->has('DKIM-Signature')); + $dkim = $headerSet->getAll('DKIM-Signature'); + $sig = reset($dkim); + $this->assertEquals($sig->getValue(), 'v=1; a=rsa-sha256; bh=f+W+hu8dIhf2VAni89o8lF6WKTXi7nViA4RrMdpD5/U=; d=dummy.nxdomain.be; h=; i=@dummy.nxdomain.be; s=dummySelector; c=simple/relaxed; t=1299879181; b=M5eomH/zamyzix9kOes+6YLzQZxuJdBP4x3nP9zF2N26eMLG2/cBKbnNyqiOTDhJdYfWPbLIa 1CWnjST0j5p4CpeOkGYuiE+M4TWEZwhRmRWootlPO3Ii6XpbBJKFk1o9zviS7OmXblUUE4aqb yRSIMDhtLdCK5GlaCneFLN7RQ='); + } + + private function createHeaderSet() + { + $cache = new Swift_KeyCache_ArrayKeyCache(new Swift_KeyCache_SimpleKeyCacheInputStream()); + $factory = new Swift_CharacterReaderFactory_SimpleCharacterReaderFactory(); + $contentEncoder = new Swift_Mime_ContentEncoder_Base64ContentEncoder(); + + $headerEncoder = new Swift_Mime_HeaderEncoder_QpHeaderEncoder(new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8')); + $paramEncoder = new Swift_Encoder_Rfc2231Encoder(new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8')); + $emailValidator = new EmailValidator(); + $headers = new Swift_Mime_SimpleHeaderSet(new Swift_Mime_SimpleHeaderFactory($headerEncoder, $paramEncoder, $emailValidator)); + + return $headers; + } + + /** + * @return Swift_Mime_Headers + */ + private function createHeaders() + { + $x = 0; + $cache = new Swift_KeyCache_ArrayKeyCache(new Swift_KeyCache_SimpleKeyCacheInputStream()); + $factory = new Swift_CharacterReaderFactory_SimpleCharacterReaderFactory(); + $contentEncoder = new Swift_Mime_ContentEncoder_Base64ContentEncoder(); + + $headerEncoder = new Swift_Mime_HeaderEncoder_QpHeaderEncoder(new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8')); + $paramEncoder = new Swift_Encoder_Rfc2231Encoder(new Swift_CharacterStream_ArrayCharacterStream($factory, 'utf-8')); + $emailValidator = new EmailValidator(); + $headerFactory = new Swift_Mime_SimpleHeaderFactory($headerEncoder, $paramEncoder, $emailValidator); + $headers = $this->getMockery('Swift_Mime_SimpleHeaderSet'); + + $headers->shouldReceive('listAll') + ->zeroOrMoreTimes() + ->andReturn(array('From', 'To', 'Date', 'Subject')); + $headers->shouldReceive('has') + ->zeroOrMoreTimes() + ->with('From') + ->andReturn(true); + $headers->shouldReceive('getAll') + ->zeroOrMoreTimes() + ->with('From') + ->andReturn(array($headerFactory->createMailboxHeader('From', 'test@test.test'))); + $headers->shouldReceive('has') + ->zeroOrMoreTimes() + ->with('To') + ->andReturn(true); + $headers->shouldReceive('getAll') + ->zeroOrMoreTimes() + ->with('To') + ->andReturn(array($headerFactory->createMailboxHeader('To', 'test@test.test'))); + $headers->shouldReceive('has') + ->zeroOrMoreTimes() + ->with('Date') + ->andReturn(true); + $headers->shouldReceive('getAll') + ->zeroOrMoreTimes() + ->with('Date') + ->andReturn(array($headerFactory->createTextHeader('Date', 'Fri, 11 Mar 2011 20:56:12 +0000 (GMT)'))); + $headers->shouldReceive('has') + ->zeroOrMoreTimes() + ->with('Subject') + ->andReturn(true); + $headers->shouldReceive('getAll') + ->zeroOrMoreTimes() + ->with('Subject') + ->andReturn(array($headerFactory->createTextHeader('Subject', 'Foo Bar Text Message'))); + $headers->shouldReceive('addTextHeader') + ->zeroOrMoreTimes() + ->with('DKIM-Signature', \Mockery::any()) + ->andReturn(true); + $headers->shouldReceive('getAll') + ->zeroOrMoreTimes() + ->with('DKIM-Signature') + ->andReturn(array($headerFactory->createTextHeader('DKIM-Signature', 'Foo Bar Text Message'))); + + return $headers; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Signers/OpenDKIMSignerTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Signers/OpenDKIMSignerTest.php new file mode 100644 index 00000000..ce99bc63 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Signers/OpenDKIMSignerTest.php @@ -0,0 +1,45 @@ +markTestSkipped( + 'Need OpenDKIM extension run these tests.' + ); + } + } + + public function testBasicSigningHeaderManipulation() + { + } + + // Default Signing + public function testSigningDefaults() + { + } + + // SHA256 Signing + public function testSigning256() + { + } + + // Relaxed/Relaxed Hash Signing + public function testSigningRelaxedRelaxed256() + { + } + + // Relaxed/Simple Hash Signing + public function testSigningRelaxedSimple256() + { + } + + // Simple/Relaxed Hash Signing + public function testSigningSimpleRelaxed256() + { + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Signers/SMimeSignerTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Signers/SMimeSignerTest.php new file mode 100644 index 00000000..aee7bceb --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Signers/SMimeSignerTest.php @@ -0,0 +1,551 @@ +replacementFactory = Swift_DependencyContainer::getInstance() + ->lookup('transport.replacementfactory'); + + $this->samplesDir = str_replace('\\', '/', realpath(__DIR__.'/../../../_samples/')).'/'; + } + + public function testUnSingedMessage() + { + $message = (new Swift_Message('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'); + + $this->assertEquals('Here is the message itself', $message->getBody()); + } + + public function testSingedMessage() + { + $message = (new Swift_Message('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'); + + $signer = new Swift_Signers_SMimeSigner(); + $signer->setSignCertificate($this->samplesDir.'smime/sign.crt', $this->samplesDir.'smime/sign.key'); + $message->attachSigner($signer); + + $messageStream = $this->newFilteredStream(); + $message->toByteStream($messageStream); + $messageStream->commit(); + + $entityString = $messageStream->getContent(); + $headers = self::getHeadersOfMessage($entityString); + + if (!($boundary = $this->getBoundary($headers['content-type']))) { + return false; + } + + $expectedBody = <<assertValidVerify($expectedBody, $messageStream); + unset($messageStream); + } + + public function testSingedMessageExtraCerts() + { + $message = (new Swift_Message('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'); + + $signer = new Swift_Signers_SMimeSigner(); + $signer->setSignCertificate($this->samplesDir.'smime/sign2.crt', $this->samplesDir.'smime/sign2.key', PKCS7_DETACHED, $this->samplesDir.'smime/intermediate.crt'); + $message->attachSigner($signer); + + $messageStream = $this->newFilteredStream(); + $message->toByteStream($messageStream); + $messageStream->commit(); + + $entityString = $messageStream->getContent(); + $headers = self::getHeadersOfMessage($entityString); + + if (!($boundary = $this->getBoundary($headers['content-type']))) { + return false; + } + + $expectedBody = <<assertValidVerify($expectedBody, $messageStream); + unset($messageStream); + } + + public function testSingedMessageBinary() + { + $message = (new Swift_Message('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'); + + $signer = new Swift_Signers_SMimeSigner(); + $signer->setSignCertificate($this->samplesDir.'smime/sign.crt', $this->samplesDir.'smime/sign.key', PKCS7_BINARY); + $message->attachSigner($signer); + + $messageStream = $this->newFilteredStream(); + $message->toByteStream($messageStream); + $messageStream->commit(); + + $entityString = $messageStream->getContent(); + $headers = self::getHeadersOfMessage($entityString); + + if (!preg_match('#^application/(x\-)?pkcs7-mime; smime-type=signed\-data;#', $headers['content-type'])) { + $this->fail('Content-type does not match.'); + + return false; + } + + $this->assertEquals($headers['content-transfer-encoding'], 'base64'); + $this->assertEquals($headers['content-disposition'], 'attachment; filename="smime.p7m"'); + + $expectedBody = '(?:^[a-zA-Z0-9\/\\r\\n+]*={0,2})'; + + $messageStreamClean = $this->newFilteredStream(); + + $this->assertValidVerify($expectedBody, $messageStream); + unset($messageStreamClean, $messageStream); + } + + public function testSingedMessageWithAttachments() + { + $message = (new Swift_Message('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'); + + $message->attach(Swift_Attachment::fromPath($this->samplesDir.'/files/textfile.zip')); + + $signer = new Swift_Signers_SMimeSigner(); + $signer->setSignCertificate($this->samplesDir.'smime/sign.crt', $this->samplesDir.'smime/sign.key'); + $message->attachSigner($signer); + + $messageStream = $this->newFilteredStream(); + $message->toByteStream($messageStream); + $messageStream->commit(); + + $entityString = $messageStream->getContent(); + $headers = self::getHeadersOfMessage($entityString); + + if (!($boundary = $this->getBoundary($headers['content-type']))) { + return false; + } + + $expectedBody = <<assertValidVerify($expectedBody, $messageStream); + unset($messageStream); + } + + public function testEncryptedMessage() + { + $message = (new Swift_Message('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'); + + $originalMessage = $this->cleanMessage($message->toString()); + + $signer = new Swift_Signers_SMimeSigner(); + $signer->setEncryptCertificate($this->samplesDir.'smime/encrypt.crt'); + $message->attachSigner($signer); + + $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); + $message->toByteStream($messageStream); + $messageStream->commit(); + + $entityString = $messageStream->getContent(); + $headers = self::getHeadersOfMessage($entityString); + + if (!preg_match('#^application/(x\-)?pkcs7-mime; smime-type=enveloped\-data;#', $headers['content-type'])) { + $this->fail('Content-type does not match.'); + + return false; + } + + $expectedBody = '(?:^[a-zA-Z0-9\/\\r\\n+]*={0,2})'; + + $decryptedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + if (!openssl_pkcs7_decrypt($messageStream->getPath(), $decryptedMessageStream->getPath(), 'file://'.$this->samplesDir.'smime/encrypt.crt', array('file://'.$this->samplesDir.'smime/encrypt.key', 'swift'))) { + $this->fail(sprintf('Decrypt of the message failed. Internal error "%s".', openssl_error_string())); + } + + $this->assertEquals($originalMessage, $decryptedMessageStream->getContent()); + unset($decryptedMessageStream, $messageStream); + } + + public function testEncryptedMessageWithMultipleCerts() + { + $message = (new Swift_Message('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'); + + $originalMessage = $this->cleanMessage($message->toString()); + + $signer = new Swift_Signers_SMimeSigner(); + $signer->setEncryptCertificate(array($this->samplesDir.'smime/encrypt.crt', $this->samplesDir.'smime/encrypt2.crt')); + $message->attachSigner($signer); + + $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); + $message->toByteStream($messageStream); + $messageStream->commit(); + + $entityString = $messageStream->getContent(); + $headers = self::getHeadersOfMessage($entityString); + + if (!preg_match('#^application/(x\-)?pkcs7-mime; smime-type=enveloped\-data;#', $headers['content-type'])) { + $this->fail('Content-type does not match.'); + + return false; + } + + $expectedBody = '(?:^[a-zA-Z0-9\/\\r\\n+]*={0,2})'; + + $decryptedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + if (!openssl_pkcs7_decrypt($messageStream->getPath(), $decryptedMessageStream->getPath(), 'file://'.$this->samplesDir.'smime/encrypt.crt', array('file://'.$this->samplesDir.'smime/encrypt.key', 'swift'))) { + $this->fail(sprintf('Decrypt of the message failed. Internal error "%s".', openssl_error_string())); + } + + $this->assertEquals($originalMessage, $decryptedMessageStream->getContent()); + unset($decryptedMessageStream); + + $decryptedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + if (!openssl_pkcs7_decrypt($messageStream->getPath(), $decryptedMessageStream->getPath(), 'file://'.$this->samplesDir.'smime/encrypt2.crt', array('file://'.$this->samplesDir.'smime/encrypt2.key', 'swift'))) { + $this->fail(sprintf('Decrypt of the message failed. Internal error "%s".', openssl_error_string())); + } + + $this->assertEquals($originalMessage, $decryptedMessageStream->getContent()); + unset($decryptedMessageStream, $messageStream); + } + + public function testSignThenEncryptedMessage() + { + $message = (new Swift_Message('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'); + + $signer = new Swift_Signers_SMimeSigner(); + $signer->setSignCertificate($this->samplesDir.'smime/sign.crt', $this->samplesDir.'smime/sign.key'); + $signer->setEncryptCertificate($this->samplesDir.'smime/encrypt.crt'); + $message->attachSigner($signer); + + $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); + $message->toByteStream($messageStream); + $messageStream->commit(); + + $entityString = $messageStream->getContent(); + $headers = self::getHeadersOfMessage($entityString); + + if (!preg_match('#^application/(x\-)?pkcs7-mime; smime-type=enveloped\-data;#', $headers['content-type'])) { + $this->fail('Content-type does not match.'); + + return false; + } + + $expectedBody = '(?:^[a-zA-Z0-9\/\\r\\n+]*={0,2})'; + + $decryptedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + if (!openssl_pkcs7_decrypt($messageStream->getPath(), $decryptedMessageStream->getPath(), 'file://'.$this->samplesDir.'smime/encrypt.crt', array('file://'.$this->samplesDir.'smime/encrypt.key', 'swift'))) { + $this->fail(sprintf('Decrypt of the message failed. Internal error "%s".', openssl_error_string())); + } + + $entityString = $decryptedMessageStream->getContent(); + $headers = self::getHeadersOfMessage($entityString); + + if (!($boundary = $this->getBoundary($headers['content-type']))) { + return false; + } + + $expectedBody = <<assertValidVerify($expectedBody, $decryptedMessageStream)) { + return false; + } + + unset($decryptedMessageStream, $messageStream); + } + + public function testEncryptThenSignMessage() + { + $message = (new Swift_Message('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'); + + $originalMessage = $this->cleanMessage($message->toString()); + + $signer = new Swift_Signers_SMimeSigner(); + $signer->setSignCertificate($this->samplesDir.'smime/sign.crt', $this->samplesDir.'smime/sign.key'); + $signer->setEncryptCertificate($this->samplesDir.'smime/encrypt.crt'); + $signer->setSignThenEncrypt(false); + $message->attachSigner($signer); + + $messageStream = $this->newFilteredStream(); + $message->toByteStream($messageStream); + $messageStream->commit(); + + $entityString = $messageStream->getContent(); + $headers = self::getHeadersOfMessage($entityString); + + if (!($boundary = $this->getBoundary($headers['content-type']))) { + return false; + } + + $expectedBody = <<MIME-Version: 1\.0 +Content-Disposition: attachment; filename="smime\.p7m" +Content-Type: application/(x\-)?pkcs7-mime; smime-type=enveloped-data; name="smime\.p7m" +Content-Transfer-Encoding: base64 + +(?:^[a-zA-Z0-9\/\\r\\n+]*={0,2}) + + +)--$boundary +Content-Type: application/(x\-)?pkcs7-signature; name="smime\.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime\.p7s" + +(?:^[a-zA-Z0-9\/\\r\\n+]*={0,2}) + +--$boundary-- +OEL; + + if (!$this->assertValidVerify($expectedBody, $messageStream)) { + return false; + } + + $expectedBody = str_replace("\n", "\r\n", $expectedBody); + if (!preg_match('%'.$expectedBody.'*%m', $entityString, $entities)) { + $this->fail('Failed regex match.'); + + return false; + } + + $messageStreamClean = new Swift_ByteStream_TemporaryFileByteStream(); + $messageStreamClean->write($entities['encrypted_message']); + + $decryptedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + if (!openssl_pkcs7_decrypt($messageStreamClean->getPath(), $decryptedMessageStream->getPath(), 'file://'.$this->samplesDir.'smime/encrypt.crt', array('file://'.$this->samplesDir.'smime/encrypt.key', 'swift'))) { + $this->fail(sprintf('Decrypt of the message failed. Internal error "%s".', openssl_error_string())); + } + + $this->assertEquals($originalMessage, $decryptedMessageStream->getContent()); + unset($messageStreamClean, $messageStream, $decryptedMessageStream); + } + + protected function assertValidVerify($expected, Swift_ByteStream_TemporaryFileByteStream $messageStream) + { + $actual = $messageStream->getContent(); + + // File is UNIX encoded so convert them to correct line ending + $expected = str_replace("\n", "\r\n", $expected); + + $actual = trim(self::getBodyOfMessage($actual)); + if (!$this->assertRegExp('%^'.$expected.'$\s*%m', $actual)) { + return false; + } + + $opensslOutput = new Swift_ByteStream_TemporaryFileByteStream(); + $verify = openssl_pkcs7_verify($messageStream->getPath(), null, $opensslOutput->getPath(), array($this->samplesDir.'smime/ca.crt')); + + if (false === $verify) { + $this->fail('Verification of the message failed.'); + + return false; + } elseif (-1 === $verify) { + $this->fail(sprintf('Verification of the message failed. Internal error "%s".', openssl_error_string())); + + return false; + } + + return true; + } + + protected function getBoundary($contentType) + { + if (!preg_match('/boundary=("[^"]+"|(?:[^\s]+|$))/is', $contentType, $contentTypeData)) { + $this->fail('Failed to find Boundary parameter'); + + return false; + } + + return trim($contentTypeData[1], '"'); + } + + protected function newFilteredStream() + { + $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'); + + return $messageStream; + } + + protected static function getBodyOfMessage($message) + { + return substr($message, strpos($message, "\r\n\r\n")); + } + + /** + * Strips of the sender headers and Mime-Version. + */ + protected function cleanMessage($content) + { + $newContent = ''; + + $headers = self::getHeadersOfMessage($content); + foreach ($headers as $headerName => $value) { + if (!in_array($headerName, array('content-type', 'content-transfer-encoding', 'content-disposition'))) { + continue; + } + + $headerName = explode('-', $headerName); + $headerName = array_map('ucfirst', $headerName); + $headerName = implode('-', $headerName); + + if (strlen($value) > 62) { + $value = wordwrap($value, 62, "\n "); + } + + $newContent .= "$headerName: $value\r\n"; + } + + return $newContent."\r\n".ltrim(self::getBodyOfMessage($content)); + } + + /** + * Returns the headers of the message. + * + * Header-names are lowercase. + * + * @param string $message + * + * @return array + */ + protected static function getHeadersOfMessage($message) + { + $headersPosEnd = strpos($message, "\r\n\r\n"); + $headerData = substr($message, 0, $headersPosEnd); + $headerLines = explode("\r\n", $headerData); + + if (empty($headerLines)) { + return array(); + } + + $headers = array(); + + foreach ($headerLines as $headerLine) { + 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]); + } + + return $headers; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/StreamFilters/ByteArrayReplacementFilterTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/StreamFilters/ByteArrayReplacementFilterTest.php new file mode 100644 index 00000000..936acaa2 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/StreamFilters/ByteArrayReplacementFilterTest.php @@ -0,0 +1,129 @@ +createFilter(array(0x61, 0x62), array(0x63, 0x64)); + $this->assertEquals( + array(0x59, 0x60, 0x63, 0x64, 0x65), + $filter->filter(array(0x59, 0x60, 0x61, 0x62, 0x65)) + ); + } + + public function testShouldBufferReturnsTrueIfPartialMatchAtEndOfBuffer() + { + $filter = $this->createFilter(array(0x61, 0x62), array(0x63, 0x64)); + $this->assertTrue($filter->shouldBuffer(array(0x59, 0x60, 0x61)), + '%s: Filter should buffer since 0x61 0x62 is the needle and the ending '. + '0x61 could be from 0x61 0x62' + ); + } + + public function testFilterCanMakeMultipleReplacements() + { + $filter = $this->createFilter(array(array(0x61), array(0x62)), array(0x63)); + $this->assertEquals( + array(0x60, 0x63, 0x60, 0x63, 0x60), + $filter->filter(array(0x60, 0x61, 0x60, 0x62, 0x60)) + ); + } + + public function testMultipleReplacementsCanBeDifferent() + { + $filter = $this->createFilter(array(array(0x61), array(0x62)), array(array(0x63), array(0x64))); + $this->assertEquals( + array(0x60, 0x63, 0x60, 0x64, 0x60), + $filter->filter(array(0x60, 0x61, 0x60, 0x62, 0x60)) + ); + } + + public function testShouldBufferReturnsFalseIfPartialMatchNotAtEndOfString() + { + $filter = $this->createFilter(array(0x0D, 0x0A), array(0x0A)); + $this->assertFalse($filter->shouldBuffer(array(0x61, 0x62, 0x0D, 0x0A, 0x63)), + '%s: Filter should not buffer since x0Dx0A is the needle and is not at EOF' + ); + } + + public function testShouldBufferReturnsTrueIfAnyOfMultipleMatchesAtEndOfString() + { + $filter = $this->createFilter(array(array(0x61, 0x62), array(0x63)), array(0x64)); + $this->assertTrue($filter->shouldBuffer(array(0x59, 0x60, 0x61)), + '%s: Filter should buffer since 0x61 0x62 is a needle and the ending '. + '0x61 could be from 0x61 0x62' + ); + } + + public function testConvertingAllLineEndingsToCRLFWhenInputIsLF() + { + $filter = $this->createFilter( + array(array(0x0D, 0x0A), array(0x0D), array(0x0A)), + array(array(0x0A), array(0x0A), array(0x0D, 0x0A)) + ); + + $this->assertEquals( + array(0x60, 0x0D, 0x0A, 0x61, 0x0D, 0x0A, 0x62, 0x0D, 0x0A, 0x63), + $filter->filter(array(0x60, 0x0A, 0x61, 0x0A, 0x62, 0x0A, 0x63)) + ); + } + + public function testConvertingAllLineEndingsToCRLFWhenInputIsCR() + { + $filter = $this->createFilter( + array(array(0x0D, 0x0A), array(0x0D), array(0x0A)), + array(array(0x0A), array(0x0A), array(0x0D, 0x0A)) + ); + + $this->assertEquals( + array(0x60, 0x0D, 0x0A, 0x61, 0x0D, 0x0A, 0x62, 0x0D, 0x0A, 0x63), + $filter->filter(array(0x60, 0x0D, 0x61, 0x0D, 0x62, 0x0D, 0x63)) + ); + } + + public function testConvertingAllLineEndingsToCRLFWhenInputIsCRLF() + { + $filter = $this->createFilter( + array(array(0x0D, 0x0A), array(0x0D), array(0x0A)), + array(array(0x0A), array(0x0A), array(0x0D, 0x0A)) + ); + + $this->assertEquals( + array(0x60, 0x0D, 0x0A, 0x61, 0x0D, 0x0A, 0x62, 0x0D, 0x0A, 0x63), + $filter->filter(array(0x60, 0x0D, 0x0A, 0x61, 0x0D, 0x0A, 0x62, 0x0D, 0x0A, 0x63)) + ); + } + + public function testConvertingAllLineEndingsToCRLFWhenInputIsLFCR() + { + $filter = $this->createFilter( + array(array(0x0D, 0x0A), array(0x0D), array(0x0A)), + array(array(0x0A), array(0x0A), array(0x0D, 0x0A)) + ); + + $this->assertEquals( + array(0x60, 0x0D, 0x0A, 0x0D, 0x0A, 0x61, 0x0D, 0x0A, 0x0D, 0x0A, 0x62, 0x0D, 0x0A, 0x0D, 0x0A, 0x63), + $filter->filter(array(0x60, 0x0A, 0x0D, 0x61, 0x0A, 0x0D, 0x62, 0x0A, 0x0D, 0x63)) + ); + } + + public function testConvertingAllLineEndingsToCRLFWhenInputContainsLFLF() + { + //Lighthouse Bug #23 + + $filter = $this->createFilter( + array(array(0x0D, 0x0A), array(0x0D), array(0x0A)), + array(array(0x0A), array(0x0A), array(0x0D, 0x0A)) + ); + + $this->assertEquals( + array(0x60, 0x0D, 0x0A, 0x0D, 0x0A, 0x61, 0x0D, 0x0A, 0x0D, 0x0A, 0x62, 0x0D, 0x0A, 0x0D, 0x0A, 0x63), + $filter->filter(array(0x60, 0x0A, 0x0A, 0x61, 0x0A, 0x0A, 0x62, 0x0A, 0x0A, 0x63)) + ); + } + + private function createFilter($search, $replace) + { + return new Swift_StreamFilters_ByteArrayReplacementFilter($search, $replace); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/StreamFilters/StringReplacementFilterFactoryTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/StreamFilters/StringReplacementFilterFactoryTest.php new file mode 100644 index 00000000..514829f6 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/StreamFilters/StringReplacementFilterFactoryTest.php @@ -0,0 +1,36 @@ +createFactory(); + $this->assertInstanceOf( + 'Swift_StreamFilters_StringReplacementFilter', + $factory->createFilter('a', 'b') + ); + } + + public function testSameInstancesAreCached() + { + $factory = $this->createFactory(); + $filter1 = $factory->createFilter('a', 'b'); + $filter2 = $factory->createFilter('a', 'b'); + $this->assertSame($filter1, $filter2, '%s: Instances should be cached'); + } + + public function testDifferingInstancesAreNotCached() + { + $factory = $this->createFactory(); + $filter1 = $factory->createFilter('a', 'b'); + $filter2 = $factory->createFilter('a', 'c'); + $this->assertNotEquals($filter1, $filter2, + '%s: Differing instances should not be cached' + ); + } + + private function createFactory() + { + return new Swift_StreamFilters_StringReplacementFilterFactory(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/StreamFilters/StringReplacementFilterTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/StreamFilters/StringReplacementFilterTest.php new file mode 100644 index 00000000..14b57eff --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/StreamFilters/StringReplacementFilterTest.php @@ -0,0 +1,59 @@ +createFilter('foo', 'bar'); + $this->assertEquals('XbarYbarZ', $filter->filter('XfooYfooZ')); + } + + public function testShouldBufferReturnsTrueIfPartialMatchAtEndOfBuffer() + { + $filter = $this->createFilter('foo', 'bar'); + $this->assertTrue($filter->shouldBuffer('XfooYf'), + '%s: Filter should buffer since "foo" is the needle and the ending '. + '"f" could be from "foo"' + ); + } + + public function testFilterCanMakeMultipleReplacements() + { + $filter = $this->createFilter(array('a', 'b'), 'foo'); + $this->assertEquals('XfooYfooZ', $filter->filter('XaYbZ')); + } + + public function testMultipleReplacementsCanBeDifferent() + { + $filter = $this->createFilter(array('a', 'b'), array('foo', 'zip')); + $this->assertEquals('XfooYzipZ', $filter->filter('XaYbZ')); + } + + public function testShouldBufferReturnsFalseIfPartialMatchNotAtEndOfString() + { + $filter = $this->createFilter("\r\n", "\n"); + $this->assertFalse($filter->shouldBuffer("foo\r\nbar"), + '%s: Filter should not buffer since x0Dx0A is the needle and is not at EOF' + ); + } + + public function testShouldBufferReturnsTrueIfAnyOfMultipleMatchesAtEndOfString() + { + $filter = $this->createFilter(array('foo', 'zip'), 'bar'); + $this->assertTrue($filter->shouldBuffer('XfooYzi'), + '%s: Filter should buffer since "zip" is a needle and the ending '. + '"zi" could be from "zip"' + ); + } + + public function testShouldBufferReturnsFalseOnEmptyBuffer() + { + $filter = $this->createFilter("\r\n", "\n"); + $this->assertFalse($filter->shouldBuffer('')); + } + + private function createFilter($search, $replace) + { + return new Swift_StreamFilters_StringReplacementFilter($search, $replace); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/AbstractSmtpEventSupportTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/AbstractSmtpEventSupportTest.php new file mode 100644 index 00000000..88141c5a --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/AbstractSmtpEventSupportTest.php @@ -0,0 +1,558 @@ +getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $listener = $this->getMockery('Swift_Events_EventListener'); + $smtp = $this->getTransport($buf, $dispatcher); + $dispatcher->shouldReceive('bindEventListener') + ->once() + ->with($listener); + + $smtp->registerPlugin($listener); + } + + public function testSendingDispatchesBeforeSendEvent() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $message = $this->createMessage(); + $smtp = $this->getTransport($buf, $dispatcher); + $evt = $this->getMockery('Swift_Events_SendEvent')->shouldIgnoreMissing(); + + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('chris@swiftmailer.org' => null)); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('mark@swiftmailer.org' => 'Mark')); + $dispatcher->shouldReceive('createSendEvent') + ->once() + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'beforeSendPerformed'); + $dispatcher->shouldReceive('dispatchEvent') + ->zeroOrMoreTimes(); + $evt->shouldReceive('bubbleCancelled') + ->zeroOrMoreTimes() + ->andReturn(false); + + $this->finishBuffer($buf); + $smtp->start(); + $this->assertEquals(1, $smtp->send($message)); + } + + public function testSendingDispatchesSendEvent() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $message = $this->createMessage(); + $smtp = $this->getTransport($buf, $dispatcher); + $evt = $this->getMockery('Swift_Events_SendEvent')->shouldIgnoreMissing(); + + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('chris@swiftmailer.org' => null)); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('mark@swiftmailer.org' => 'Mark')); + $dispatcher->shouldReceive('createSendEvent') + ->once() + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'sendPerformed'); + $dispatcher->shouldReceive('dispatchEvent') + ->zeroOrMoreTimes(); + $evt->shouldReceive('bubbleCancelled') + ->zeroOrMoreTimes() + ->andReturn(false); + + $this->finishBuffer($buf); + $smtp->start(); + $this->assertEquals(1, $smtp->send($message)); + } + + public function testSendEventCapturesFailures() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_SendEvent')->shouldIgnoreMissing(); + $smtp = $this->getTransport($buf, $dispatcher); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('chris@swiftmailer.org' => null)); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('mark@swiftmailer.org' => 'Mark')); + $buf->shouldReceive('write') + ->once() + ->with("MAIL FROM:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250 OK\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn("500 Not now\r\n"); + $dispatcher->shouldReceive('createSendEvent') + ->zeroOrMoreTimes() + ->with($smtp, \Mockery::any()) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'sendPerformed'); + $dispatcher->shouldReceive('dispatchEvent') + ->zeroOrMoreTimes(); + $evt->shouldReceive('bubbleCancelled') + ->zeroOrMoreTimes() + ->andReturn(false); + $evt->shouldReceive('setFailedRecipients') + ->once() + ->with(array('mark@swiftmailer.org')); + + $this->finishBuffer($buf); + $smtp->start(); + $this->assertEquals(0, $smtp->send($message)); + } + + public function testSendEventHasResultFailedIfAllFailures() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_SendEvent')->shouldIgnoreMissing(); + $smtp = $this->getTransport($buf, $dispatcher); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('chris@swiftmailer.org' => null)); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('mark@swiftmailer.org' => 'Mark')); + $buf->shouldReceive('write') + ->once() + ->with("MAIL FROM:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250 OK\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn("500 Not now\r\n"); + $dispatcher->shouldReceive('createSendEvent') + ->zeroOrMoreTimes() + ->with($smtp, \Mockery::any()) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'sendPerformed'); + $dispatcher->shouldReceive('dispatchEvent') + ->zeroOrMoreTimes(); + $evt->shouldReceive('bubbleCancelled') + ->zeroOrMoreTimes() + ->andReturn(false); + $evt->shouldReceive('setResult') + ->once() + ->with(Swift_Events_SendEvent::RESULT_FAILED); + + $this->finishBuffer($buf); + $smtp->start(); + $this->assertEquals(0, $smtp->send($message)); + } + + public function testSendEventHasResultTentativeIfSomeFailures() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_SendEvent')->shouldIgnoreMissing(); + $smtp = $this->getTransport($buf, $dispatcher); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('chris@swiftmailer.org' => null)); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array( + 'mark@swiftmailer.org' => 'Mark', + 'chris@site.tld' => 'Chris', + )); + $buf->shouldReceive('write') + ->once() + ->with("MAIL FROM:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250 OK\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn("500 Not now\r\n"); + $dispatcher->shouldReceive('createSendEvent') + ->zeroOrMoreTimes() + ->with($smtp, \Mockery::any()) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'sendPerformed'); + $dispatcher->shouldReceive('dispatchEvent') + ->zeroOrMoreTimes(); + $evt->shouldReceive('bubbleCancelled') + ->zeroOrMoreTimes() + ->andReturn(false); + $evt->shouldReceive('setResult') + ->once() + ->with(Swift_Events_SendEvent::RESULT_TENTATIVE); + + $this->finishBuffer($buf); + $smtp->start(); + $this->assertEquals(1, $smtp->send($message)); + } + + public function testSendEventHasResultSuccessIfNoFailures() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_SendEvent')->shouldIgnoreMissing(); + $smtp = $this->getTransport($buf, $dispatcher); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('chris@swiftmailer.org' => null)); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array( + 'mark@swiftmailer.org' => 'Mark', + 'chris@site.tld' => 'Chris', + )); + $dispatcher->shouldReceive('createSendEvent') + ->zeroOrMoreTimes() + ->with($smtp, \Mockery::any()) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'sendPerformed'); + $dispatcher->shouldReceive('dispatchEvent') + ->zeroOrMoreTimes(); + $evt->shouldReceive('bubbleCancelled') + ->zeroOrMoreTimes() + ->andReturn(false); + $evt->shouldReceive('setResult') + ->once() + ->with(Swift_Events_SendEvent::RESULT_SUCCESS); + + $this->finishBuffer($buf); + $smtp->start(); + $this->assertEquals(2, $smtp->send($message)); + } + + public function testCancellingEventBubbleBeforeSendStopsEvent() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_SendEvent')->shouldIgnoreMissing(); + $smtp = $this->getTransport($buf, $dispatcher); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('chris@swiftmailer.org' => null)); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('mark@swiftmailer.org' => 'Mark')); + $dispatcher->shouldReceive('createSendEvent') + ->zeroOrMoreTimes() + ->with($smtp, \Mockery::any()) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'beforeSendPerformed'); + $dispatcher->shouldReceive('dispatchEvent') + ->zeroOrMoreTimes(); + $evt->shouldReceive('bubbleCancelled') + ->atLeast()->once() + ->andReturn(true); + + $this->finishBuffer($buf); + $smtp->start(); + $this->assertEquals(0, $smtp->send($message)); + } + + public function testStartingTransportDispatchesTransportChangeEvent() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_TransportChangeEvent'); + $smtp = $this->getTransport($buf, $dispatcher); + + $dispatcher->shouldReceive('createTransportChangeEvent') + ->atLeast()->once() + ->with($smtp) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'transportStarted'); + $dispatcher->shouldReceive('dispatchEvent') + ->zeroOrMoreTimes(); + $evt->shouldReceive('bubbleCancelled') + ->atLeast()->once() + ->andReturn(false); + + $this->finishBuffer($buf); + $smtp->start(); + } + + public function testStartingTransportDispatchesBeforeTransportChangeEvent() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_TransportChangeEvent'); + $smtp = $this->getTransport($buf, $dispatcher); + + $dispatcher->shouldReceive('createTransportChangeEvent') + ->atLeast()->once() + ->with($smtp) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'beforeTransportStarted'); + $dispatcher->shouldReceive('dispatchEvent') + ->zeroOrMoreTimes(); + $evt->shouldReceive('bubbleCancelled') + ->atLeast()->once() + ->andReturn(false); + + $this->finishBuffer($buf); + $smtp->start(); + } + + public function testCancellingBubbleBeforeTransportStartStopsEvent() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_TransportChangeEvent'); + $smtp = $this->getTransport($buf, $dispatcher); + + $dispatcher->shouldReceive('createTransportChangeEvent') + ->atLeast()->once() + ->with($smtp) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'beforeTransportStarted'); + $dispatcher->shouldReceive('dispatchEvent') + ->zeroOrMoreTimes(); + $evt->shouldReceive('bubbleCancelled') + ->atLeast()->once() + ->andReturn(true); + + $this->finishBuffer($buf); + $smtp->start(); + + $this->assertFalse($smtp->isStarted(), + '%s: Transport should not be started since event bubble was cancelled' + ); + } + + public function testStoppingTransportDispatchesTransportChangeEvent() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_TransportChangeEvent')->shouldIgnoreMissing(); + $smtp = $this->getTransport($buf, $dispatcher); + + $dispatcher->shouldReceive('createTransportChangeEvent') + ->atLeast()->once() + ->with($smtp) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'transportStopped'); + $dispatcher->shouldReceive('dispatchEvent') + ->zeroOrMoreTimes(); + + $this->finishBuffer($buf); + $smtp->start(); + $smtp->stop(); + } + + public function testStoppingTransportDispatchesBeforeTransportChangeEvent() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_TransportChangeEvent')->shouldIgnoreMissing(); + $smtp = $this->getTransport($buf, $dispatcher); + + $dispatcher->shouldReceive('createTransportChangeEvent') + ->atLeast()->once() + ->with($smtp) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'beforeTransportStopped'); + $dispatcher->shouldReceive('dispatchEvent') + ->zeroOrMoreTimes(); + + $this->finishBuffer($buf); + $smtp->start(); + $smtp->stop(); + } + + public function testCancellingBubbleBeforeTransportStoppedStopsEvent() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_TransportChangeEvent'); + $smtp = $this->getTransport($buf, $dispatcher); + + $hasRun = false; + $dispatcher->shouldReceive('createTransportChangeEvent') + ->atLeast()->once() + ->with($smtp) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'beforeTransportStopped') + ->andReturnUsing(function () use (&$hasRun) { + $hasRun = true; + }); + $dispatcher->shouldReceive('dispatchEvent') + ->zeroOrMoreTimes(); + $evt->shouldReceive('bubbleCancelled') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$hasRun) { + return $hasRun; + }); + + $this->finishBuffer($buf); + $smtp->start(); + $smtp->stop(); + + $this->assertTrue($smtp->isStarted(), + '%s: Transport should not be stopped since event bubble was cancelled' + ); + } + + public function testResponseEventsAreGenerated() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_ResponseEvent'); + $smtp = $this->getTransport($buf, $dispatcher); + + $dispatcher->shouldReceive('createResponseEvent') + ->atLeast()->once() + ->with($smtp, \Mockery::any(), \Mockery::any()) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->atLeast()->once() + ->with($evt, 'responseReceived'); + + $this->finishBuffer($buf); + $smtp->start(); + } + + public function testCommandEventsAreGenerated() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_CommandEvent'); + $smtp = $this->getTransport($buf, $dispatcher); + + $dispatcher->shouldReceive('createCommandEvent') + ->once() + ->with($smtp, \Mockery::any(), \Mockery::any()) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'commandSent'); + + $this->finishBuffer($buf); + $smtp->start(); + } + + public function testExceptionsCauseExceptionEvents() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_TransportExceptionEvent'); + $smtp = $this->getTransport($buf, $dispatcher); + + $buf->shouldReceive('readLine') + ->atLeast()->once() + ->andReturn("503 I'm sleepy, go away!\r\n"); + $dispatcher->shouldReceive('createTransportExceptionEvent') + ->zeroOrMoreTimes() + ->with($smtp, \Mockery::any()) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->once() + ->with($evt, 'exceptionThrown'); + $evt->shouldReceive('bubbleCancelled') + ->atLeast()->once() + ->andReturn(false); + + try { + $smtp->start(); + $this->fail('TransportException should be thrown on invalid response'); + } catch (Swift_TransportException $e) { + } + } + + public function testExceptionBubblesCanBeCancelled() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(false); + $evt = $this->getMockery('Swift_Events_TransportExceptionEvent'); + $smtp = $this->getTransport($buf, $dispatcher); + + $buf->shouldReceive('readLine') + ->atLeast()->once() + ->andReturn("503 I'm sleepy, go away!\r\n"); + $dispatcher->shouldReceive('createTransportExceptionEvent') + ->twice() + ->with($smtp, \Mockery::any()) + ->andReturn($evt); + $dispatcher->shouldReceive('dispatchEvent') + ->twice() + ->with($evt, 'exceptionThrown'); + $evt->shouldReceive('bubbleCancelled') + ->atLeast()->once() + ->andReturn(true); + + $this->finishBuffer($buf); + $smtp->start(); + } + + protected function createEventDispatcher($stub = true) + { + return $this->getMockery('Swift_Events_EventDispatcher')->shouldIgnoreMissing(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/AbstractSmtpTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/AbstractSmtpTest.php new file mode 100644 index 00000000..58b58ed4 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/AbstractSmtpTest.php @@ -0,0 +1,1316 @@ +getBuffer(); + $smtp = $this->getTransport($buf); + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 some.server.tld bleh\r\n"); + + $this->finishBuffer($buf); + try { + $this->assertFalse($smtp->isStarted(), '%s: SMTP should begin non-started'); + $smtp->start(); + $this->assertTrue($smtp->isStarted(), '%s: start() should have started connection'); + } catch (Exception $e) { + $this->fail('220 is a valid SMTP greeting and should be accepted'); + } + } + + public function testBadGreetingCausesException() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("554 I'm busy\r\n"); + $this->finishBuffer($buf); + try { + $this->assertFalse($smtp->isStarted(), '%s: SMTP should begin non-started'); + $smtp->start(); + $this->fail('554 greeting indicates an error and should cause an exception'); + } catch (Exception $e) { + $this->assertFalse($smtp->isStarted(), '%s: start() should have failed'); + } + } + + public function testStartSendsHeloToInitiate() + { + /* -- RFC 2821, 3.2. + + 3.2 Client Initiation + + Once the server has sent the welcoming message and the client has + received it, the client normally sends the EHLO command to the + server, indicating the client's identity. In addition to opening the + session, use of EHLO indicates that the client is able to process + service extensions and requests that the server provide a list of the + extensions it supports. Older SMTP systems which are unable to + support service extensions and contemporary clients which do not + require service extensions in the mail session being initiated, MAY + use HELO instead of EHLO. Servers MUST NOT return the extended + EHLO-style response to a HELO command. For a particular connection + attempt, if the server returns a "command not recognized" response to + EHLO, the client SHOULD be able to fall back and send HELO. + + In the EHLO command the host sending the command identifies itself; + the command may be interpreted as saying "Hello, I am " (and, + in the case of EHLO, "and I support service extension requests"). + + -- RFC 2281, 4.1.1.1. + + ehlo = "EHLO" SP Domain CRLF + helo = "HELO" SP Domain CRLF + + -- RFC 2821, 4.3.2. + + EHLO or HELO + S: 250 + E: 504, 550 + + */ + + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 some.server.tld bleh\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^HELO example.org\r\n$~D') + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('250 ServerName'."\r\n"); + + $this->finishBuffer($buf); + try { + $smtp->start(); + } catch (Exception $e) { + $this->fail('Starting SMTP should send HELO and accept 250 response'); + } + } + + public function testInvalidHeloResponseCausesException() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 some.server.tld bleh\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^HELO example.org\r\n$~D') + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('504 WTF'."\r\n"); + + $this->finishBuffer($buf); + try { + $this->assertFalse($smtp->isStarted(), '%s: SMTP should begin non-started'); + $smtp->start(); + $this->fail('Non 250 HELO response should raise Exception'); + } catch (Exception $e) { + $this->assertFalse($smtp->isStarted(), '%s: SMTP start() should have failed'); + } + } + + public function testDomainNameIsPlacedInHelo() + { + /* -- RFC 2821, 4.1.4. + + The SMTP client MUST, if possible, ensure that the domain parameter + to the EHLO command is a valid principal host name (not a CNAME or MX + name) for its host. If this is not possible (e.g., when the client's + address is dynamically assigned and the client does not have an + obvious name), an address literal SHOULD be substituted for the + domain name and supplemental information provided that will assist in + identifying the client. + */ + + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 some.server.tld bleh\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("HELO mydomain.com\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('250 ServerName'."\r\n"); + + $this->finishBuffer($buf); + $smtp->setLocalDomain('mydomain.com'); + $smtp->start(); + } + + public function testSuccessfulMailCommand() + { + /* -- RFC 2821, 3.3. + + There are three steps to SMTP mail transactions. The transaction + starts with a MAIL command which gives the sender identification. + + ..... + + The first step in the procedure is the MAIL command. + + MAIL FROM: [SP ] + + -- RFC 2821, 4.1.1.2. + + Syntax: + + "MAIL FROM:" ("<>" / Reverse-Path) + [SP Mail-parameters] CRLF + -- RFC 2821, 4.1.2. + + Reverse-path = Path + Forward-path = Path + Path = "<" [ A-d-l ":" ] Mailbox ">" + A-d-l = At-domain *( "," A-d-l ) + ; Note that this form, the so-called "source route", + ; MUST BE accepted, SHOULD NOT be generated, and SHOULD be + ; ignored. + At-domain = "@" domain + + -- RFC 2821, 4.3.2. + + MAIL + S: 250 + E: 552, 451, 452, 550, 553, 503 + */ + + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo@bar' => null)); + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('write') + ->once() + ->with("MAIL FROM:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250 OK\r\n"); + + $this->finishBuffer($buf); + try { + $smtp->start(); + $smtp->send($message); + } catch (Exception $e) { + $this->fail('MAIL FROM should accept a 250 response'); + } + } + + public function testInvalidResponseCodeFromMailCausesException() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo@bar' => null)); + $buf->shouldReceive('write') + ->once() + ->with("MAIL FROM:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('553 Bad'."\r\n"); + + $this->finishBuffer($buf); + try { + $smtp->start(); + $smtp->send($message); + $this->fail('MAIL FROM should accept a 250 response'); + } catch (Exception $e) { + } + } + + public function testSenderIsPreferredOverFrom() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getSender') + ->once() + ->andReturn(array('another@domain.com' => 'Someone')); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo@bar' => null)); + $buf->shouldReceive('write') + ->once() + ->with("MAIL FROM:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('250 OK'."\r\n"); + + $this->finishBuffer($buf); + $smtp->start(); + $smtp->send($message); + } + + public function testReturnPathIsPreferredOverSender() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getSender') + ->once() + ->andReturn(array('another@domain.com' => 'Someone')); + $message->shouldReceive('getReturnPath') + ->once() + ->andReturn('more@domain.com'); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo@bar' => null)); + $buf->shouldReceive('write') + ->once() + ->with("MAIL FROM:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('250 OK'."\r\n"); + + $this->finishBuffer($buf); + $smtp->start(); + $smtp->send($message); + } + + public function testSuccessfulRcptCommandWith250Response() + { + /* -- RFC 2821, 3.3. + + The second step in the procedure is the RCPT command. + + RCPT TO: [ SP ] + + The first or only argument to this command includes a forward-path + (normally a mailbox and domain, always surrounded by "<" and ">" + brackets) identifying one recipient. If accepted, the SMTP server + returns a 250 OK reply and stores the forward-path. If the recipient + is known not to be a deliverable address, the SMTP server returns a + 550 reply, typically with a string such as "no such user - " and the + mailbox name (other circumstances and reply codes are possible). + This step of the procedure can be repeated any number of times. + + -- RFC 2821, 4.1.1.3. + + This command is used to identify an individual recipient of the mail + data; multiple recipients are specified by multiple use of this + command. The argument field contains a forward-path and may contain + optional parameters. + + The forward-path normally consists of the required destination + mailbox. Sending systems SHOULD not generate the optional list of + hosts known as a source route. + + ....... + + "RCPT TO:" ("" / "" / Forward-Path) + [SP Rcpt-parameters] CRLF + + -- RFC 2821, 4.2.2. + + 250 Requested mail action okay, completed + 251 User not local; will forward to + (See section 3.4) + 252 Cannot VRFY user, but will accept message and attempt + delivery + + -- RFC 2821, 4.3.2. + + RCPT + S: 250, 251 (but see section 3.4 for discussion of 251 and 551) + E: 550, 551, 552, 553, 450, 451, 452, 503, 550 + */ + + //We'll treat 252 as accepted since it isn't really a failure + + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo@bar' => null)); + $buf->shouldReceive('write') + ->once() + ->with("MAIL FROM:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('250 OK'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn('250 OK'."\r\n"); + + $this->finishBuffer($buf); + try { + $smtp->start(); + $smtp->send($message); + } catch (Exception $e) { + $this->fail('RCPT TO should accept a 250 response'); + } + } + + public function testMailFromCommandIsOnlySentOncePerMessage() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo@bar' => null)); + $buf->shouldReceive('write') + ->once() + ->with("MAIL FROM:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('250 OK'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn('250 OK'."\r\n"); + $buf->shouldReceive('write') + ->never() + ->with("MAIL FROM:\r\n"); + + $this->finishBuffer($buf); + $smtp->start(); + $smtp->send($message); + } + + public function testMultipleRecipientsSendsMultipleRcpt() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array( + 'foo@bar' => null, + 'zip@button' => 'Zip Button', + 'test@domain' => 'Test user', + )); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('250 OK'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn('250 OK'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(3); + $buf->shouldReceive('readLine') + ->once() + ->with(3) + ->andReturn('250 OK'."\r\n"); + + $this->finishBuffer($buf); + $smtp->start(); + $smtp->send($message); + } + + public function testCcRecipientsSendsMultipleRcpt() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo@bar' => null)); + $message->shouldReceive('getCc') + ->once() + ->andReturn(array( + 'zip@button' => 'Zip Button', + 'test@domain' => 'Test user', + )); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('250 OK'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn('250 OK'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(3); + $buf->shouldReceive('readLine') + ->once() + ->with(3) + ->andReturn('250 OK'."\r\n"); + + $this->finishBuffer($buf); + $smtp->start(); + $smtp->send($message); + } + + public function testSendReturnsNumberOfSuccessfulRecipients() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo@bar' => null)); + $message->shouldReceive('getCc') + ->once() + ->andReturn(array( + 'zip@button' => 'Zip Button', + 'test@domain' => 'Test user', + )); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('250 OK'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn('501 Nobody here'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(3); + $buf->shouldReceive('readLine') + ->once() + ->with(3) + ->andReturn('250 OK'."\r\n"); + + $this->finishBuffer($buf); + $smtp->start(); + $this->assertEquals(2, $smtp->send($message), + '%s: 1 of 3 recipients failed so 2 should be returned' + ); + } + + public function testRsetIsSentIfNoSuccessfulRecipients() + { + /* --RFC 2821, 4.1.1.5. + + This command specifies that the current mail transaction will be + aborted. Any stored sender, recipients, and mail data MUST be + discarded, and all buffers and state tables cleared. The receiver + MUST send a "250 OK" reply to a RSET command with no arguments. A + reset command may be issued by the client at any time. + + -- RFC 2821, 4.3.2. + + RSET + S: 250 + */ + + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo@bar' => null)); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('503 Bad'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RSET\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn('250 OK'."\r\n"); + + $this->finishBuffer($buf); + $smtp->start(); + $this->assertEquals(0, $smtp->send($message), + '%s: 1 of 1 recipients failed so 0 should be returned' + ); + } + + public function testSuccessfulDataCommand() + { + /* -- RFC 2821, 3.3. + + The third step in the procedure is the DATA command (or some + alternative specified in a service extension). + + DATA + + If accepted, the SMTP server returns a 354 Intermediate reply and + considers all succeeding lines up to but not including the end of + mail data indicator to be the message text. + + -- RFC 2821, 4.1.1.4. + + The receiver normally sends a 354 response to DATA, and then treats + the lines (strings ending in sequences, as described in + section 2.3.7) following the command as mail data from the sender. + This command causes the mail data to be appended to the mail data + buffer. The mail data may contain any of the 128 ASCII character + codes, although experience has indicated that use of control + characters other than SP, HT, CR, and LF may cause problems and + SHOULD be avoided when possible. + + -- RFC 2821, 4.3.2. + + DATA + I: 354 -> data -> S: 250 + E: 552, 554, 451, 452 + E: 451, 554, 503 + */ + + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo@bar' => null)); + $buf->shouldReceive('write') + ->once() + ->with("DATA\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('354 Go ahead'."\r\n"); + + $this->finishBuffer($buf); + try { + $smtp->start(); + $smtp->send($message); + } catch (Exception $e) { + $this->fail('354 is the expected response to DATA'); + } + } + + public function testBadDataResponseCausesException() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo@bar' => null)); + $buf->shouldReceive('write') + ->once() + ->with("DATA\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('451 Bad'."\r\n"); + + $this->finishBuffer($buf); + try { + $smtp->start(); + $smtp->send($message); + $this->fail('354 is the expected response to DATA (not observed)'); + } catch (Exception $e) { + } + } + + public function testMessageIsStreamedToBufferForData() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo@bar' => null)); + $buf->shouldReceive('write') + ->once() + ->with("DATA\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('354 OK'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("\r\n.\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn('250 OK'."\r\n"); + + $this->finishBuffer($buf); + $smtp->start(); + $smtp->send($message); + } + + public function testBadResponseAfterDataTransmissionCausesException() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->once() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->once() + ->andReturn(array('foo@bar' => null)); + $buf->shouldReceive('write') + ->once() + ->with("DATA\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('354 OK'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("\r\n.\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn('554 Error'."\r\n"); + + $this->finishBuffer($buf); + try { + $smtp->start(); + $smtp->send($message); + $this->fail('250 is the expected response after a DATA transmission (not observed)'); + } catch (Exception $e) { + } + } + + public function testBccRecipientsAreRemovedFromHeaders() + { + /* -- RFC 2821, 7.2. + + Addresses that do not appear in the message headers may appear in the + RCPT commands to an SMTP server for a number of reasons. The two + most common involve the use of a mailing address as a "list exploder" + (a single address that resolves into multiple addresses) and the + appearance of "blind copies". Especially when more than one RCPT + command is present, and in order to avoid defeating some of the + purpose of these mechanisms, SMTP clients and servers SHOULD NOT copy + the full set of RCPT command arguments into the headers, either as + part of trace headers or as informational or private-extension + headers. Since this rule is often violated in practice, and cannot + be enforced, sending SMTP systems that are aware of "bcc" use MAY + find it helpful to send each blind copy as a separate message + transaction containing only a single RCPT command. + */ + + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('foo@bar' => null)); + $message->shouldReceive('getBcc') + ->zeroOrMoreTimes() + ->andReturn(array( + 'zip@button' => 'Zip Button', + 'test@domain' => 'Test user', + )); + $message->shouldReceive('setBcc') + ->once() + ->with(array()); + $message->shouldReceive('setBcc') + ->zeroOrMoreTimes(); + + $this->finishBuffer($buf); + $smtp->start(); + $smtp->send($message); + } + + public function testEachBccRecipientIsSentASeparateMessage() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('foo@bar' => null)); + $message->shouldReceive('getBcc') + ->zeroOrMoreTimes() + ->andReturn(array( + 'zip@button' => 'Zip Button', + 'test@domain' => 'Test user', + )); + $message->shouldReceive('setBcc') + ->atLeast()->once() + ->with(array()); + $message->shouldReceive('setBcc') + ->once() + ->with(array('zip@button' => 'Zip Button')); + $message->shouldReceive('setBcc') + ->once() + ->with(array('test@domain' => 'Test user')); + $message->shouldReceive('setBcc') + ->atLeast()->once() + ->with(array( + 'zip@button' => 'Zip Button', + 'test@domain' => 'Test user', + )); + + $buf->shouldReceive('write')->once()->with("MAIL FROM:\r\n")->andReturn(1); + $buf->shouldReceive('readLine')->once()->with(1)->andReturn("250 OK\r\n"); + $buf->shouldReceive('write')->once()->with("RCPT TO:\r\n")->andReturn(2); + $buf->shouldReceive('readLine')->once()->with(2)->andReturn("250 OK\r\n"); + $buf->shouldReceive('write')->once()->with("DATA\r\n")->andReturn(3); + $buf->shouldReceive('readLine')->once()->with(3)->andReturn("354 OK\r\n"); + $buf->shouldReceive('write')->once()->with("\r\n.\r\n")->andReturn(4); + $buf->shouldReceive('readLine')->once()->with(4)->andReturn("250 OK\r\n"); + + $buf->shouldReceive('write')->once()->with("MAIL FROM:\r\n")->andReturn(5); + $buf->shouldReceive('readLine')->once()->with(5)->andReturn("250 OK\r\n"); + $buf->shouldReceive('write')->once()->with("RCPT TO:\r\n")->andReturn(6); + $buf->shouldReceive('readLine')->once()->with(6)->andReturn("250 OK\r\n"); + $buf->shouldReceive('write')->once()->with("DATA\r\n")->andReturn(7); + $buf->shouldReceive('readLine')->once()->with(7)->andReturn("354 OK\r\n"); + $buf->shouldReceive('write')->once()->with("\r\n.\r\n")->andReturn(8); + $buf->shouldReceive('readLine')->once()->with(8)->andReturn("250 OK\r\n"); + + $buf->shouldReceive('write')->once()->with("MAIL FROM:\r\n")->andReturn(9); + $buf->shouldReceive('readLine')->once()->with(9)->andReturn("250 OK\r\n"); + $buf->shouldReceive('write')->once()->with("RCPT TO:\r\n")->andReturn(10); + $buf->shouldReceive('readLine')->once()->with(10)->andReturn("250 OK\r\n"); + $buf->shouldReceive('write')->once()->with("DATA\r\n")->andReturn(11); + $buf->shouldReceive('readLine')->once()->with(11)->andReturn("354 OK\r\n"); + $buf->shouldReceive('write')->once()->with("\r\n.\r\n")->andReturn(12); + $buf->shouldReceive('readLine')->once()->with(12)->andReturn("250 OK\r\n"); + + $this->finishBuffer($buf); + $smtp->start(); + $this->assertEquals(3, $smtp->send($message)); + } + + public function testMessageStateIsRestoredOnFailure() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('foo@bar' => null)); + $message->shouldReceive('getBcc') + ->zeroOrMoreTimes() + ->andReturn(array( + 'zip@button' => 'Zip Button', + 'test@domain' => 'Test user', + )); + $message->shouldReceive('setBcc') + ->once() + ->with(array()); + $message->shouldReceive('setBcc') + ->once() + ->with(array( + 'zip@button' => 'Zip Button', + 'test@domain' => 'Test user', + )); + $buf->shouldReceive('write') + ->once() + ->with("MAIL FROM:\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250 OK\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn("250 OK\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("DATA\r\n") + ->andReturn(3); + $buf->shouldReceive('readLine') + ->once() + ->with(3) + ->andReturn("451 No\r\n"); + + $this->finishBuffer($buf); + + $smtp->start(); + try { + $smtp->send($message); + $this->fail('A bad response was given so exception is expected'); + } catch (Exception $e) { + } + } + + public function testStopSendsQuitCommand() + { + /* -- RFC 2821, 4.1.1.10. + + This command specifies that the receiver MUST send an OK reply, and + then close the transmission channel. + + The receiver MUST NOT intentionally close the transmission channel + until it receives and replies to a QUIT command (even if there was an + error). The sender MUST NOT intentionally close the transmission + channel until it sends a QUIT command and SHOULD wait until it + receives the reply (even if there was an error response to a previous + command). If the connection is closed prematurely due to violations + of the above or system or network failure, the server MUST cancel any + pending transaction, but not undo any previously completed + transaction, and generally MUST act as if the command or transaction + in progress had received a temporary error (i.e., a 4yz response). + + The QUIT command may be issued at any time. + + Syntax: + "QUIT" CRLF + */ + + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('write') + ->once() + ->with("QUIT\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("221 Bye\r\n"); + $buf->shouldReceive('terminate') + ->once(); + + $this->finishBuffer($buf); + + $this->assertFalse($smtp->isStarted()); + $smtp->start(); + $this->assertTrue($smtp->isStarted()); + $smtp->stop(); + $this->assertFalse($smtp->isStarted()); + } + + public function testBufferCanBeFetched() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $ref = $smtp->getBuffer(); + $this->assertEquals($buf, $ref); + } + + public function testBufferCanBeWrittenToUsingExecuteCommand() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + $buf->shouldReceive('write') + ->zeroOrMoreTimes() + ->with("FOO\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->zeroOrMoreTimes() + ->with(1) + ->andReturn("250 OK\r\n"); + + $res = $smtp->executeCommand("FOO\r\n"); + $this->assertEquals("250 OK\r\n", $res); + } + + public function testResponseCodesAreValidated() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + $buf->shouldReceive('write') + ->zeroOrMoreTimes() + ->with("FOO\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->zeroOrMoreTimes() + ->with(1) + ->andReturn("551 Not ok\r\n"); + + try { + $smtp->executeCommand("FOO\r\n", array(250, 251)); + $this->fail('A 250 or 251 response was needed but 551 was returned.'); + } catch (Exception $e) { + } + } + + public function testFailedRecipientsCanBeCollectedByReference() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('foo@bar' => null)); + $message->shouldReceive('getBcc') + ->zeroOrMoreTimes() + ->andReturn(array( + 'zip@button' => 'Zip Button', + 'test@domain' => 'Test user', + )); + $message->shouldReceive('setBcc') + ->atLeast()->once() + ->with(array()); + $message->shouldReceive('setBcc') + ->once() + ->with(array('zip@button' => 'Zip Button')); + $message->shouldReceive('setBcc') + ->once() + ->with(array('test@domain' => 'Test user')); + $message->shouldReceive('setBcc') + ->atLeast()->once() + ->with(array( + 'zip@button' => 'Zip Button', + 'test@domain' => 'Test user', + )); + + $buf->shouldReceive('write')->once()->with("MAIL FROM:\r\n")->andReturn(1); + $buf->shouldReceive('readLine')->once()->with(1)->andReturn("250 OK\r\n"); + $buf->shouldReceive('write')->once()->with("RCPT TO:\r\n")->andReturn(2); + $buf->shouldReceive('readLine')->once()->with(2)->andReturn("250 OK\r\n"); + $buf->shouldReceive('write')->once()->with("DATA\r\n")->andReturn(3); + $buf->shouldReceive('readLine')->once()->with(3)->andReturn("354 OK\r\n"); + $buf->shouldReceive('write')->once()->with("\r\n.\r\n")->andReturn(4); + $buf->shouldReceive('readLine')->once()->with(4)->andReturn("250 OK\r\n"); + + $buf->shouldReceive('write')->once()->with("MAIL FROM:\r\n")->andReturn(5); + $buf->shouldReceive('readLine')->once()->with(5)->andReturn("250 OK\r\n"); + $buf->shouldReceive('write')->once()->with("RCPT TO:\r\n")->andReturn(6); + $buf->shouldReceive('readLine')->once()->with(6)->andReturn("500 Bad\r\n"); + $buf->shouldReceive('write')->once()->with("RSET\r\n")->andReturn(7); + $buf->shouldReceive('readLine')->once()->with(7)->andReturn("250 OK\r\n"); + + $buf->shouldReceive('write')->once()->with("MAIL FROM:\r\n")->andReturn(9); + $buf->shouldReceive('readLine')->once()->with(9)->andReturn("250 OK\r\n"); + $buf->shouldReceive('write')->once()->with("RCPT TO:\r\n")->andReturn(10); + $buf->shouldReceive('readLine')->once()->with(10)->andReturn("500 Bad\r\n"); + $buf->shouldReceive('write')->once()->with("RSET\r\n")->andReturn(11); + $buf->shouldReceive('readLine')->once()->with(11)->andReturn("250 OK\r\n"); + + $this->finishBuffer($buf); + $smtp->start(); + $this->assertEquals(1, $smtp->send($message, $failures)); + $this->assertEquals(array('zip@button', 'test@domain'), $failures, + '%s: Failures should be caught in an array' + ); + } + + public function testSendingRegeneratesMessageId() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $message = $this->createMessage(); + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('me@domain.com' => 'Me')); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('foo@bar' => null)); + $message->shouldReceive('generateId') + ->once(); + + $this->finishBuffer($buf); + $smtp->start(); + $smtp->send($message); + } + + public function testPing() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 some.server.tld bleh\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^NOOP\r\n$~D') + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('250 OK'."\r\n"); + + $this->finishBuffer($buf); + $this->assertTrue($smtp->ping()); + } + + public function testPingOnDeadConnection() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 some.server.tld bleh\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^NOOP\r\n$~D') + ->andThrow('Swift_TransportException'); + + $this->finishBuffer($buf); + $smtp->start(); + $this->assertTrue($smtp->isStarted()); + $this->assertFalse($smtp->ping()); + $this->assertFalse($smtp->isStarted()); + } + + public function testSetLocalDomain() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + + $smtp->setLocalDomain('example.com'); + $this->assertEquals('example.com', $smtp->getLocalDomain()); + + $smtp->setLocalDomain('192.168.0.1'); + $this->assertEquals('[192.168.0.1]', $smtp->getLocalDomain()); + + $smtp->setLocalDomain('[192.168.0.1]'); + $this->assertEquals('[192.168.0.1]', $smtp->getLocalDomain()); + + $smtp->setLocalDomain('fd00::'); + $this->assertEquals('[IPv6:fd00::]', $smtp->getLocalDomain()); + + $smtp->setLocalDomain('[IPv6:fd00::]'); + $this->assertEquals('[IPv6:fd00::]', $smtp->getLocalDomain()); + } + + protected function getBuffer() + { + return $this->getMockery('Swift_Transport_IoBuffer')->shouldIgnoreMissing(); + } + + protected function createMessage() + { + return $this->getMockery('Swift_Mime_SimpleMessage')->shouldIgnoreMissing(); + } + + protected function finishBuffer($buf) + { + $buf->shouldReceive('readLine') + ->zeroOrMoreTimes() + ->with(0) + ->andReturn('220 server.com foo'."\r\n"); + $buf->shouldReceive('write') + ->zeroOrMoreTimes() + ->with('~^(EH|HE)LO .*?\r\n$~D') + ->andReturn($x = uniqid('', true)); + $buf->shouldReceive('readLine') + ->zeroOrMoreTimes() + ->with($x) + ->andReturn('250 ServerName'."\r\n"); + $buf->shouldReceive('write') + ->zeroOrMoreTimes() + ->with('~^MAIL FROM:<.*?>\r\n$~D') + ->andReturn($x = uniqid('', true)); + $buf->shouldReceive('readLine') + ->zeroOrMoreTimes() + ->with($x) + ->andReturn("250 OK\r\n"); + $buf->shouldReceive('write') + ->zeroOrMoreTimes() + ->with('~^RCPT TO:<.*?>\r\n$~D') + ->andReturn($x = uniqid('', true)); + $buf->shouldReceive('readLine') + ->zeroOrMoreTimes() + ->with($x) + ->andReturn("250 OK\r\n"); + $buf->shouldReceive('write') + ->zeroOrMoreTimes() + ->with("DATA\r\n") + ->andReturn($x = uniqid('', true)); + $buf->shouldReceive('readLine') + ->zeroOrMoreTimes() + ->with($x) + ->andReturn("354 OK\r\n"); + $buf->shouldReceive('write') + ->zeroOrMoreTimes() + ->with("\r\n.\r\n") + ->andReturn($x = uniqid('', true)); + $buf->shouldReceive('readLine') + ->zeroOrMoreTimes() + ->with($x) + ->andReturn("250 OK\r\n"); + $buf->shouldReceive('write') + ->zeroOrMoreTimes() + ->with("RSET\r\n") + ->andReturn($x = uniqid('', true)); + $buf->shouldReceive('readLine') + ->zeroOrMoreTimes() + ->with($x) + ->andReturn("250 OK\r\n"); + + $buf->shouldReceive('write') + ->zeroOrMoreTimes() + ->andReturn(false); + $buf->shouldReceive('readLine') + ->zeroOrMoreTimes() + ->andReturn(false); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/CramMd5AuthenticatorTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/CramMd5AuthenticatorTest.php new file mode 100644 index 00000000..01a9c10d --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/CramMd5AuthenticatorTest.php @@ -0,0 +1,64 @@ +agent = $this->getMockery('Swift_Transport_SmtpAgent')->shouldIgnoreMissing(); + } + + public function testKeywordIsCramMd5() + { + /* -- RFC 2195, 2. + The authentication type associated with CRAM is "CRAM-MD5". + */ + + $cram = $this->getAuthenticator(); + $this->assertEquals('CRAM-MD5', $cram->getAuthKeyword()); + } + + public function testSuccessfulAuthentication() + { + $cram = $this->getAuthenticator(); + + $this->agent->shouldReceive('executeCommand') + ->once() + ->with("AUTH CRAM-MD5\r\n", array(334)) + ->andReturn('334 '.base64_encode('')."\r\n"); + $this->agent->shouldReceive('executeCommand') + ->once() + ->with(\Mockery::any(), array(235)); + + $this->assertTrue($cram->authenticate($this->agent, 'jack', 'pass'), + '%s: The buffer accepted all commands authentication should succeed' + ); + } + + public function testAuthenticationFailureSendRsetAndReturnFalse() + { + $cram = $this->getAuthenticator(); + + $this->agent->shouldReceive('executeCommand') + ->once() + ->with("AUTH CRAM-MD5\r\n", array(334)) + ->andReturn('334 '.base64_encode('')."\r\n"); + $this->agent->shouldReceive('executeCommand') + ->once() + ->with(\Mockery::any(), array(235)) + ->andThrow(new Swift_TransportException('')); + $this->agent->shouldReceive('executeCommand') + ->once() + ->with("RSET\r\n", array(250)); + + $this->assertFalse($cram->authenticate($this->agent, 'jack', 'pass'), + '%s: Authentication fails, so RSET should be sent' + ); + } + + private function getAuthenticator() + { + return new Swift_Transport_Esmtp_Auth_CramMd5Authenticator(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/LoginAuthenticatorTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/LoginAuthenticatorTest.php new file mode 100644 index 00000000..4ca83410 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/LoginAuthenticatorTest.php @@ -0,0 +1,64 @@ +agent = $this->getMockery('Swift_Transport_SmtpAgent')->shouldIgnoreMissing(); + } + + public function testKeywordIsLogin() + { + $login = $this->getAuthenticator(); + $this->assertEquals('LOGIN', $login->getAuthKeyword()); + } + + public function testSuccessfulAuthentication() + { + $login = $this->getAuthenticator(); + + $this->agent->shouldReceive('executeCommand') + ->once() + ->with("AUTH LOGIN\r\n", array(334)); + $this->agent->shouldReceive('executeCommand') + ->once() + ->with(base64_encode('jack')."\r\n", array(334)); + $this->agent->shouldReceive('executeCommand') + ->once() + ->with(base64_encode('pass')."\r\n", array(235)); + + $this->assertTrue($login->authenticate($this->agent, 'jack', 'pass'), + '%s: The buffer accepted all commands authentication should succeed' + ); + } + + public function testAuthenticationFailureSendRsetAndReturnFalse() + { + $login = $this->getAuthenticator(); + + $this->agent->shouldReceive('executeCommand') + ->once() + ->with("AUTH LOGIN\r\n", array(334)); + $this->agent->shouldReceive('executeCommand') + ->once() + ->with(base64_encode('jack')."\r\n", array(334)); + $this->agent->shouldReceive('executeCommand') + ->once() + ->with(base64_encode('pass')."\r\n", array(235)) + ->andThrow(new Swift_TransportException('')); + $this->agent->shouldReceive('executeCommand') + ->once() + ->with("RSET\r\n", array(250)); + + $this->assertFalse($login->authenticate($this->agent, 'jack', 'pass'), + '%s: Authentication fails, so RSET should be sent' + ); + } + + private function getAuthenticator() + { + return new Swift_Transport_Esmtp_Auth_LoginAuthenticator(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/NTLMAuthenticatorTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/NTLMAuthenticatorTest.php new file mode 100644 index 00000000..d781c2d8 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/NTLMAuthenticatorTest.php @@ -0,0 +1,201 @@ +markTestSkipped('One of the required functions is not available.'); + } + } + + public function testKeywordIsNtlm() + { + $login = $this->getAuthenticator(); + $this->assertEquals('NTLM', $login->getAuthKeyword()); + } + + public function testMessage1Generator() + { + $login = $this->getAuthenticator(); + $message1 = $this->invokePrivateMethod('createMessage1', $login); + + $this->assertEquals($this->message1, bin2hex($message1), '%s: We send the smallest ntlm message which should never fail.'); + } + + public function testLMv1Generator() + { + $password = 'test1234'; + $challenge = 'b019d38bad875c9d'; + $lmv1 = '1879f60127f8a877022132ec221bcbf3ca016a9f76095606'; + + $login = $this->getAuthenticator(); + $lmv1Result = $this->invokePrivateMethod('createLMPassword', $login, array($password, hex2bin($challenge))); + + $this->assertEquals($lmv1, bin2hex($lmv1Result), '%s: The keys should be the same cause we use the same values to generate them.'); + } + + public function testLMv2Generator() + { + $username = 'user'; + $password = 'SecREt01'; + $domain = 'DOMAIN'; + $challenge = '0123456789abcdef'; + $lmv2 = 'd6e6152ea25d03b7c6ba6629c2d6aaf0ffffff0011223344'; + + $login = $this->getAuthenticator(); + $lmv2Result = $this->invokePrivateMethod('createLMv2Password', $login, array($password, $username, $domain, hex2bin($challenge), hex2bin('ffffff0011223344'))); + + $this->assertEquals($lmv2, bin2hex($lmv2Result), '%s: The keys should be the same cause we use the same values to generate them.'); + } + + public function testMessage3v1Generator() + { + $username = 'test'; + $domain = 'TESTNT'; + $workstation = 'MEMBER'; + $lmResponse = '1879f60127f8a877022132ec221bcbf3ca016a9f76095606'; + $ntlmResponse = 'e6285df3287c5d194f84df1a94817c7282d09754b6f9e02a'; + $message3T = '4e544c4d5353500003000000180018006000000018001800780000000c000c0040000000080008004c0000000c000c0054000000000000009a0000000102000054004500530054004e00540074006500730074004d0045004d004200450052001879f60127f8a877022132ec221bcbf3ca016a9f76095606e6285df3287c5d194f84df1a94817c7282d09754b6f9e02a'; + + $login = $this->getAuthenticator(); + $message3 = $this->invokePrivateMethod('createMessage3', $login, array($domain, $username, $workstation, hex2bin($lmResponse), hex2bin($ntlmResponse))); + + $this->assertEquals($message3T, bin2hex($message3), '%s: We send the same information as the example is created with so this should be the same'); + } + + public function testMessage3v2Generator() + { + $username = 'test'; + $domain = 'TESTNT'; + $workstation = 'MEMBER'; + $lmResponse = 'bf2e015119f6bdb3f6fdb768aa12d478f5ce3d2401c8f6e9'; + $ntlmResponse = 'caa4da8f25d5e840974ed8976d3ada46010100000000000030fa7e3c677bc301f5ce3d2401c8f6e90000000002000c0054004500530054004e00540001000c004d0045004d0042004500520003001e006d0065006d006200650072002e0074006500730074002e0063006f006d000000000000000000'; + + $login = $this->getAuthenticator(); + $message3 = $this->invokePrivateMethod('createMessage3', $login, array($domain, $username, $workstation, hex2bin($lmResponse), hex2bin($ntlmResponse))); + + $this->assertEquals($this->message3, bin2hex($message3), '%s: We send the same information as the example is created with so this should be the same'); + } + + public function testGetDomainAndUsername() + { + $username = "DOMAIN\user"; + + $login = $this->getAuthenticator(); + list($domain, $user) = $this->invokePrivateMethod('getDomainAndUsername', $login, array($username)); + + $this->assertEquals('DOMAIN', $domain, '%s: the fetched domain did not match'); + $this->assertEquals('user', $user, '%s: the fetched user did not match'); + } + + public function testGetDomainAndUsernameWithExtension() + { + $username = "domain.com\user"; + + $login = $this->getAuthenticator(); + list($domain, $user) = $this->invokePrivateMethod('getDomainAndUsername', $login, array($username)); + + $this->assertEquals('domain.com', $domain, '%s: the fetched domain did not match'); + $this->assertEquals('user', $user, '%s: the fetched user did not match'); + } + + public function testGetDomainAndUsernameWithAtSymbol() + { + $username = 'user@DOMAIN'; + + $login = $this->getAuthenticator(); + list($domain, $user) = $this->invokePrivateMethod('getDomainAndUsername', $login, array($username)); + + $this->assertEquals('DOMAIN', $domain, '%s: the fetched domain did not match'); + $this->assertEquals('user', $user, '%s: the fetched user did not match'); + } + + public function testGetDomainAndUsernameWithAtSymbolAndExtension() + { + $username = 'user@domain.com'; + + $login = $this->getAuthenticator(); + list($domain, $user) = $this->invokePrivateMethod('getDomainAndUsername', $login, array($username)); + + $this->assertEquals('domain.com', $domain, '%s: the fetched domain did not match'); + $this->assertEquals('user', $user, '%s: the fetched user did not match'); + } + + public function testGetDomainAndUsernameWithoutDomain() + { + $username = 'user'; + + $login = $this->getAuthenticator(); + list($domain, $user) = $this->invokePrivateMethod('getDomainAndUsername', $login, array($username)); + + $this->assertEquals('', $domain, '%s: the fetched domain did not match'); + $this->assertEquals('user', $user, '%s: the fetched user did not match'); + } + + public function testSuccessfulAuthentication() + { + $domain = 'TESTNT'; + $username = 'test'; + $secret = 'test1234'; + + $ntlm = $this->getAuthenticator(); + $agent = $this->getAgent(); + $agent->shouldReceive('executeCommand') + ->once() + ->with('AUTH NTLM '.base64_encode( + $this->invokePrivateMethod('createMessage1', $ntlm) + )."\r\n", array(334)) + ->andReturn('334 '.base64_encode(hex2bin('4e544c4d53535000020000000c000c003000000035828980514246973ea892c10000000000000000460046003c00000054004500530054004e00540002000c0054004500530054004e00540001000c004d0045004d0042004500520003001e006d0065006d006200650072002e0074006500730074002e0063006f006d0000000000'))); + $agent->shouldReceive('executeCommand') + ->once() + ->with(base64_encode( + $this->invokePrivateMethod('createMessage3', $ntlm, array($domain, $username, hex2bin('4d0045004d00420045005200'), hex2bin('bf2e015119f6bdb3f6fdb768aa12d478f5ce3d2401c8f6e9'), hex2bin('caa4da8f25d5e840974ed8976d3ada46010100000000000030fa7e3c677bc301f5ce3d2401c8f6e90000000002000c0054004500530054004e00540001000c004d0045004d0042004500520003001e006d0065006d006200650072002e0074006500730074002e0063006f006d000000000000000000')) + ))."\r\n", array(235)); + + $this->assertTrue($ntlm->authenticate($agent, $username.'@'.$domain, $secret, hex2bin('30fa7e3c677bc301'), hex2bin('f5ce3d2401c8f6e9')), '%s: The buffer accepted all commands authentication should succeed'); + } + + public function testAuthenticationFailureSendRsetAndReturnFalse() + { + $domain = 'TESTNT'; + $username = 'test'; + $secret = 'test1234'; + + $ntlm = $this->getAuthenticator(); + $agent = $this->getAgent(); + $agent->shouldReceive('executeCommand') + ->once() + ->with('AUTH NTLM '.base64_encode( + $this->invokePrivateMethod('createMessage1', $ntlm) + )."\r\n", array(334)) + ->andThrow(new Swift_TransportException('')); + $agent->shouldReceive('executeCommand') + ->once() + ->with("RSET\r\n", array(250)); + + $this->assertFalse($ntlm->authenticate($agent, $username.'@'.$domain, $secret, hex2bin('30fa7e3c677bc301'), hex2bin('f5ce3d2401c8f6e9')), '%s: Authentication fails, so RSET should be sent'); + } + + private function getAuthenticator() + { + return new Swift_Transport_Esmtp_Auth_NTLMAuthenticator(); + } + + private function getAgent() + { + return $this->getMockery('Swift_Transport_SmtpAgent')->shouldIgnoreMissing(); + } + + private function invokePrivateMethod($method, $instance, array $args = array()) + { + $methodC = new ReflectionMethod($instance, trim($method)); + $methodC->setAccessible(true); + + return $methodC->invokeArgs($instance, $args); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/PlainAuthenticatorTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/PlainAuthenticatorTest.php new file mode 100644 index 00000000..c6c40420 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/Auth/PlainAuthenticatorTest.php @@ -0,0 +1,67 @@ +agent = $this->getMockery('Swift_Transport_SmtpAgent')->shouldIgnoreMissing(); + } + + public function testKeywordIsPlain() + { + /* -- RFC 4616, 1. + The name associated with this mechanism is "PLAIN". + */ + + $login = $this->getAuthenticator(); + $this->assertEquals('PLAIN', $login->getAuthKeyword()); + } + + public function testSuccessfulAuthentication() + { + /* -- RFC 4616, 2. + The client presents the authorization identity (identity to act as), + followed by a NUL (U+0000) character, followed by the authentication + identity (identity whose password will be used), followed by a NUL + (U+0000) character, followed by the clear-text password. + */ + + $plain = $this->getAuthenticator(); + + $this->agent->shouldReceive('executeCommand') + ->once() + ->with('AUTH PLAIN '.base64_encode( + 'jack'.chr(0).'jack'.chr(0).'pass' + )."\r\n", array(235)); + + $this->assertTrue($plain->authenticate($this->agent, 'jack', 'pass'), + '%s: The buffer accepted all commands authentication should succeed' + ); + } + + public function testAuthenticationFailureSendRsetAndReturnFalse() + { + $plain = $this->getAuthenticator(); + + $this->agent->shouldReceive('executeCommand') + ->once() + ->with('AUTH PLAIN '.base64_encode( + 'jack'.chr(0).'jack'.chr(0).'pass' + )."\r\n", array(235)) + ->andThrow(new Swift_TransportException('')); + $this->agent->shouldReceive('executeCommand') + ->once() + ->with("RSET\r\n", array(250)); + + $this->assertFalse($plain->authenticate($this->agent, 'jack', 'pass'), + '%s: Authentication fails, so RSET should be sent' + ); + } + + private function getAuthenticator() + { + return new Swift_Transport_Esmtp_Auth_PlainAuthenticator(); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/AuthHandlerTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/AuthHandlerTest.php new file mode 100644 index 00000000..dadff3b0 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/Esmtp/AuthHandlerTest.php @@ -0,0 +1,165 @@ +agent = $this->getMockery('Swift_Transport_SmtpAgent')->shouldIgnoreMissing(); + } + + public function testKeywordIsAuth() + { + $auth = $this->createHandler(array()); + $this->assertEquals('AUTH', $auth->getHandledKeyword()); + } + + public function testUsernameCanBeSetAndFetched() + { + $auth = $this->createHandler(array()); + $auth->setUsername('jack'); + $this->assertEquals('jack', $auth->getUsername()); + } + + public function testPasswordCanBeSetAndFetched() + { + $auth = $this->createHandler(array()); + $auth->setPassword('pass'); + $this->assertEquals('pass', $auth->getPassword()); + } + + public function testAuthModeCanBeSetAndFetched() + { + $auth = $this->createHandler(array()); + $auth->setAuthMode('PLAIN'); + $this->assertEquals('PLAIN', $auth->getAuthMode()); + } + + public function testMixinMethods() + { + $auth = $this->createHandler(array()); + $mixins = $auth->exposeMixinMethods(); + $this->assertTrue(in_array('getUsername', $mixins), + '%s: getUsername() should be accessible via mixin' + ); + $this->assertTrue(in_array('setUsername', $mixins), + '%s: setUsername() should be accessible via mixin' + ); + $this->assertTrue(in_array('getPassword', $mixins), + '%s: getPassword() should be accessible via mixin' + ); + $this->assertTrue(in_array('setPassword', $mixins), + '%s: setPassword() should be accessible via mixin' + ); + $this->assertTrue(in_array('setAuthMode', $mixins), + '%s: setAuthMode() should be accessible via mixin' + ); + $this->assertTrue(in_array('getAuthMode', $mixins), + '%s: getAuthMode() should be accessible via mixin' + ); + } + + public function testAuthenticatorsAreCalledAccordingToParamsAfterEhlo() + { + $a1 = $this->createMockAuthenticator('PLAIN'); + $a2 = $this->createMockAuthenticator('LOGIN'); + + $a1->shouldReceive('authenticate') + ->never() + ->with($this->agent, 'jack', 'pass'); + $a2->shouldReceive('authenticate') + ->once() + ->with($this->agent, 'jack', 'pass') + ->andReturn(true); + + $auth = $this->createHandler(array($a1, $a2)); + $auth->setUsername('jack'); + $auth->setPassword('pass'); + + $auth->setKeywordParams(array('CRAM-MD5', 'LOGIN')); + $auth->afterEhlo($this->agent); + } + + public function testAuthenticatorsAreNotUsedIfNoUsernameSet() + { + $a1 = $this->createMockAuthenticator('PLAIN'); + $a2 = $this->createMockAuthenticator('LOGIN'); + + $a1->shouldReceive('authenticate') + ->never() + ->with($this->agent, 'jack', 'pass'); + $a2->shouldReceive('authenticate') + ->never() + ->with($this->agent, 'jack', 'pass') + ->andReturn(true); + + $auth = $this->createHandler(array($a1, $a2)); + + $auth->setKeywordParams(array('CRAM-MD5', 'LOGIN')); + $auth->afterEhlo($this->agent); + } + + public function testSeveralAuthenticatorsAreTriedIfNeeded() + { + $a1 = $this->createMockAuthenticator('PLAIN'); + $a2 = $this->createMockAuthenticator('LOGIN'); + + $a1->shouldReceive('authenticate') + ->once() + ->with($this->agent, 'jack', 'pass') + ->andReturn(false); + $a2->shouldReceive('authenticate') + ->once() + ->with($this->agent, 'jack', 'pass') + ->andReturn(true); + + $auth = $this->createHandler(array($a1, $a2)); + $auth->setUsername('jack'); + $auth->setPassword('pass'); + + $auth->setKeywordParams(array('PLAIN', 'LOGIN')); + $auth->afterEhlo($this->agent); + } + + public function testFirstAuthenticatorToPassBreaksChain() + { + $a1 = $this->createMockAuthenticator('PLAIN'); + $a2 = $this->createMockAuthenticator('LOGIN'); + $a3 = $this->createMockAuthenticator('CRAM-MD5'); + + $a1->shouldReceive('authenticate') + ->once() + ->with($this->agent, 'jack', 'pass') + ->andReturn(false); + $a2->shouldReceive('authenticate') + ->once() + ->with($this->agent, 'jack', 'pass') + ->andReturn(true); + $a3->shouldReceive('authenticate') + ->never() + ->with($this->agent, 'jack', 'pass'); + + $auth = $this->createHandler(array($a1, $a2)); + $auth->setUsername('jack'); + $auth->setPassword('pass'); + + $auth->setKeywordParams(array('PLAIN', 'LOGIN', 'CRAM-MD5')); + $auth->afterEhlo($this->agent); + } + + private function createHandler($authenticators) + { + return new Swift_Transport_Esmtp_AuthHandler($authenticators); + } + + private function createMockAuthenticator($type) + { + $authenticator = $this->getMockery('Swift_Transport_Esmtp_Authenticator')->shouldIgnoreMissing(); + $authenticator->shouldReceive('getAuthKeyword') + ->zeroOrMoreTimes() + ->andReturn($type); + + return $authenticator; + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/EsmtpTransport/ExtensionSupportTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/EsmtpTransport/ExtensionSupportTest.php new file mode 100644 index 00000000..2b8e919b --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/EsmtpTransport/ExtensionSupportTest.php @@ -0,0 +1,561 @@ +getBuffer(); + $smtp = $this->getTransport($buf); + $ext1 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $ext2 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + + $ext1->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('AUTH'); + $ext1->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('STARTTLS') + ->andReturn(1); + $ext2->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('STARTTLS'); + $ext2->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('AUTH') + ->andReturn(-1); + $this->finishBuffer($buf); + + $smtp->setExtensionHandlers(array($ext1, $ext2)); + $this->assertEquals(array($ext2, $ext1), $smtp->getExtensionHandlers()); + } + + public function testHandlersAreNotifiedOfParams() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $ext1 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $ext2 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 server.com foo\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^EHLO .*?\r\n$~D') + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250-ServerName.tld\r\n"); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250-AUTH PLAIN LOGIN\r\n"); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250 SIZE=123456\r\n"); + + $ext1->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('AUTH'); + $ext1->shouldReceive('setKeywordParams') + ->once() + ->with(array('PLAIN', 'LOGIN')); + $ext2->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('SIZE'); + $ext2->shouldReceive('setKeywordParams') + ->zeroOrMoreTimes() + ->with(array('123456')); + $this->finishBuffer($buf); + + $smtp->setExtensionHandlers(array($ext1, $ext2)); + $smtp->start(); + } + + public function testSupportedExtensionHandlersAreRunAfterEhlo() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $ext1 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $ext2 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $ext3 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 server.com foo\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^EHLO .*?\r\n$~D') + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250-ServerName.tld\r\n"); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250-AUTH PLAIN LOGIN\r\n"); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250 SIZE=123456\r\n"); + + $ext1->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('AUTH'); + $ext1->shouldReceive('afterEhlo') + ->once() + ->with($smtp); + $ext2->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('SIZE'); + $ext2->shouldReceive('afterEhlo') + ->zeroOrMoreTimes() + ->with($smtp); + $ext3->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('STARTTLS'); + $ext3->shouldReceive('afterEhlo') + ->never() + ->with($smtp); + $this->finishBuffer($buf); + + $smtp->setExtensionHandlers(array($ext1, $ext2, $ext3)); + $smtp->start(); + } + + public function testExtensionsCanModifyMailFromParams() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(); + $smtp = new Swift_Transport_EsmtpTransport($buf, array(), $dispatcher, 'example.org'); + $ext1 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $ext2 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $ext3 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('me@domain' => 'Me')); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('foo@bar' => null)); + + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 server.com foo\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^EHLO .*?\r\n$~D') + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250-ServerName.tld\r\n"); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250-AUTH PLAIN LOGIN\r\n"); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250 SIZE=123456\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("MAIL FROM: FOO ZIP\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn("250 OK\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO:\r\n") + ->andReturn(3); + $buf->shouldReceive('readLine') + ->once() + ->with(3) + ->andReturn("250 OK\r\n"); + $this->finishBuffer($buf); + + $ext1->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('AUTH'); + $ext1->shouldReceive('getMailParams') + ->once() + ->andReturn('FOO'); + $ext1->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('STARTTLS') + ->andReturn(1); + $ext1->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('SIZE') + ->andReturn(-1); + $ext2->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('SIZE'); + $ext2->shouldReceive('getMailParams') + ->once() + ->andReturn('ZIP'); + $ext2->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('AUTH') + ->andReturn(1); + $ext2->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('STARTTLS') + ->andReturn(1); + $ext3->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('STARTTLS'); + $ext3->shouldReceive('getMailParams') + ->never(); + $ext3->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('AUTH') + ->andReturn(-1); + $ext3->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('SIZE') + ->andReturn(-1); + + $smtp->setExtensionHandlers(array($ext1, $ext2, $ext3)); + $smtp->start(); + $smtp->send($message); + } + + public function testExtensionsCanModifyRcptParams() + { + $buf = $this->getBuffer(); + $dispatcher = $this->createEventDispatcher(); + $smtp = new Swift_Transport_EsmtpTransport($buf, array(), $dispatcher, 'example.org'); + $ext1 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $ext2 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $ext3 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $message = $this->createMessage(); + + $message->shouldReceive('getFrom') + ->zeroOrMoreTimes() + ->andReturn(array('me@domain' => 'Me')); + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('foo@bar' => null)); + + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 server.com foo\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^EHLO .+?\r\n$~D') + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250-ServerName.tld\r\n"); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250-AUTH PLAIN LOGIN\r\n"); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250 SIZE=123456\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("MAIL FROM:\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn("250 OK\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("RCPT TO: FOO ZIP\r\n") + ->andReturn(3); + $buf->shouldReceive('readLine') + ->once() + ->with(3) + ->andReturn("250 OK\r\n"); + $this->finishBuffer($buf); + + $ext1->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('AUTH'); + $ext1->shouldReceive('getRcptParams') + ->once() + ->andReturn('FOO'); + $ext1->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('STARTTLS') + ->andReturn(1); + $ext1->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('SIZE') + ->andReturn(-1); + $ext2->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('SIZE'); + $ext2->shouldReceive('getRcptParams') + ->once() + ->andReturn('ZIP'); + $ext2->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('STARTTLS') + ->andReturn(1); + $ext2->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('AUTH') + ->andReturn(1); + $ext3->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('STARTTLS'); + $ext3->shouldReceive('getRcptParams') + ->never(); + $ext3->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('AUTH') + ->andReturn(-1); + $ext3->shouldReceive('getPriorityOver') + ->zeroOrMoreTimes() + ->with('SIZE') + ->andReturn(-1); + + $smtp->setExtensionHandlers(array($ext1, $ext2, $ext3)); + $smtp->start(); + $smtp->send($message); + } + + public function testExtensionsAreNotifiedOnCommand() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $ext1 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $ext2 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $ext3 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 server.com foo\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^EHLO .+?\r\n$~D') + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250-ServerName.tld\r\n"); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250-AUTH PLAIN LOGIN\r\n"); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250 SIZE=123456\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("FOO\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn("250 Cool\r\n"); + $this->finishBuffer($buf); + + $ext1->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('AUTH'); + $ext1->shouldReceive('onCommand') + ->once() + ->with($smtp, "FOO\r\n", array(250, 251), \Mockery::any(), \Mockery::any()); + $ext2->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('SIZE'); + $ext2->shouldReceive('onCommand') + ->once() + ->with($smtp, "FOO\r\n", array(250, 251), \Mockery::any(), \Mockery::any()); + $ext3->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('STARTTLS'); + $ext3->shouldReceive('onCommand') + ->never() + ->with(\Mockery::any(), \Mockery::any(), \Mockery::any(), \Mockery::any(), \Mockery::any()); + + $smtp->setExtensionHandlers(array($ext1, $ext2, $ext3)); + $smtp->start(); + $smtp->executeCommand("FOO\r\n", array(250, 251)); + } + + public function testChainOfCommandAlgorithmWhenNotifyingExtensions() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $ext1 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $ext2 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + $ext3 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 server.com foo\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^EHLO .+?\r\n$~D') + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250-ServerName.tld\r\n"); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250-AUTH PLAIN LOGIN\r\n"); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn("250 SIZE=123456\r\n"); + $buf->shouldReceive('write') + ->never() + ->with("FOO\r\n"); + $this->finishBuffer($buf); + + $ext1->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('AUTH'); + $ext1->shouldReceive('onCommand') + ->once() + ->with($smtp, "FOO\r\n", array(250, 251), \Mockery::any(), \Mockery::any()) + ->andReturnUsing(function ($a, $b, $c, $d, &$e) { + $e = true; + + return '250 ok'; + }); + $ext2->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('SIZE'); + $ext2->shouldReceive('onCommand') + ->never() + ->with(\Mockery::any(), \Mockery::any(), \Mockery::any(), \Mockery::any()); + + $ext3->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('STARTTLS'); + $ext3->shouldReceive('onCommand') + ->never() + ->with(\Mockery::any(), \Mockery::any(), \Mockery::any(), \Mockery::any()); + + $smtp->setExtensionHandlers(array($ext1, $ext2, $ext3)); + $smtp->start(); + $smtp->executeCommand("FOO\r\n", array(250, 251)); + } + + public function testExtensionsCanExposeMixinMethods() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $ext1 = $this->getMockery('Swift_Transport_EsmtpHandlerMixin')->shouldIgnoreMissing(); + $ext2 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + + $ext1->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('AUTH'); + $ext1->shouldReceive('exposeMixinMethods') + ->zeroOrMoreTimes() + ->andReturn(array('setUsername', 'setPassword')); + $ext1->shouldReceive('setUsername') + ->once() + ->with('mick'); + $ext1->shouldReceive('setPassword') + ->once() + ->with('pass'); + $ext2->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('STARTTLS'); + $this->finishBuffer($buf); + + $smtp->setExtensionHandlers(array($ext1, $ext2)); + $smtp->setUsername('mick'); + $smtp->setPassword('pass'); + } + + public function testMixinMethodsBeginningWithSetAndNullReturnAreFluid() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $ext1 = $this->getMockery('Swift_Transport_EsmtpHandlerMixin')->shouldIgnoreMissing(); + $ext2 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + + $ext1->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('AUTH'); + $ext1->shouldReceive('exposeMixinMethods') + ->zeroOrMoreTimes() + ->andReturn(array('setUsername', 'setPassword')); + $ext1->shouldReceive('setUsername') + ->once() + ->with('mick') + ->andReturn(null); + $ext1->shouldReceive('setPassword') + ->once() + ->with('pass') + ->andReturn(null); + $ext2->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('STARTTLS'); + $this->finishBuffer($buf); + + $smtp->setExtensionHandlers(array($ext1, $ext2)); + $ret = $smtp->setUsername('mick'); + $this->assertEquals($smtp, $ret); + $ret = $smtp->setPassword('pass'); + $this->assertEquals($smtp, $ret); + } + + public function testMixinSetterWhichReturnValuesAreNotFluid() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $ext1 = $this->getMockery('Swift_Transport_EsmtpHandlerMixin')->shouldIgnoreMissing(); + $ext2 = $this->getMockery('Swift_Transport_EsmtpHandler')->shouldIgnoreMissing(); + + $ext1->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('AUTH'); + $ext1->shouldReceive('exposeMixinMethods') + ->zeroOrMoreTimes() + ->andReturn(array('setUsername', 'setPassword')); + $ext1->shouldReceive('setUsername') + ->once() + ->with('mick') + ->andReturn('x'); + $ext1->shouldReceive('setPassword') + ->once() + ->with('pass') + ->andReturn('x'); + $ext2->shouldReceive('getHandledKeyword') + ->zeroOrMoreTimes() + ->andReturn('STARTTLS'); + $this->finishBuffer($buf); + + $smtp->setExtensionHandlers(array($ext1, $ext2)); + $this->assertEquals('x', $smtp->setUsername('mick')); + $this->assertEquals('x', $smtp->setPassword('pass')); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/EsmtpTransportTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/EsmtpTransportTest.php new file mode 100644 index 00000000..647ae939 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/EsmtpTransportTest.php @@ -0,0 +1,298 @@ +createEventDispatcher(); + } + + return new Swift_Transport_EsmtpTransport($buf, array(), $dispatcher, 'example.org'); + } + + public function testHostCanBeSetAndFetched() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $smtp->setHost('foo'); + $this->assertEquals('foo', $smtp->getHost(), '%s: Host should be returned'); + } + + public function testPortCanBeSetAndFetched() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $smtp->setPort(25); + $this->assertEquals(25, $smtp->getPort(), '%s: Port should be returned'); + } + + public function testTimeoutCanBeSetAndFetched() + { + $buf = $this->getBuffer(); + $buf->shouldReceive('setParam') + ->once() + ->with('timeout', 10); + + $smtp = $this->getTransport($buf); + $smtp->setTimeout(10); + $this->assertEquals(10, $smtp->getTimeout(), '%s: Timeout should be returned'); + } + + public function testEncryptionCanBeSetAndFetched() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $smtp->setEncryption('tls'); + $this->assertEquals('tls', $smtp->getEncryption(), '%s: Crypto should be returned'); + } + + public function testStartSendsHeloToInitiate() + { + // previous loop would fail if there is an issue + $this->addToAssertionCount(1); + } + + public function testStartSendsEhloToInitiate() + { + /* -- RFC 2821, 3.2. + + 3.2 Client Initiation + + Once the server has sent the welcoming message and the client has + received it, the client normally sends the EHLO command to the + server, indicating the client's identity. In addition to opening the + session, use of EHLO indicates that the client is able to process + service extensions and requests that the server provide a list of the + extensions it supports. Older SMTP systems which are unable to + support service extensions and contemporary clients which do not + require service extensions in the mail session being initiated, MAY + use HELO instead of EHLO. Servers MUST NOT return the extended + EHLO-style response to a HELO command. For a particular connection + attempt, if the server returns a "command not recognized" response to + EHLO, the client SHOULD be able to fall back and send HELO. + + In the EHLO command the host sending the command identifies itself; + the command may be interpreted as saying "Hello, I am " (and, + in the case of EHLO, "and I support service extension requests"). + + -- RFC 2281, 4.1.1.1. + + ehlo = "EHLO" SP Domain CRLF + helo = "HELO" SP Domain CRLF + + -- RFC 2821, 4.3.2. + + EHLO or HELO + S: 250 + E: 504, 550 + + */ + + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 some.server.tld bleh\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^EHLO .+?\r\n$~D') + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('250 ServerName'."\r\n"); + + $this->finishBuffer($buf); + try { + $smtp->start(); + } catch (Exception $e) { + $this->fail('Starting Esmtp should send EHLO and accept 250 response: '.$e->getMessage()); + } + } + + public function testHeloIsUsedAsFallback() + { + /* -- RFC 2821, 4.1.4. + + If the EHLO command is not acceptable to the SMTP server, 501, 500, + or 502 failure replies MUST be returned as appropriate. The SMTP + server MUST stay in the same state after transmitting these replies + that it was in before the EHLO was received. + */ + + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 some.server.tld bleh\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^EHLO .+?\r\n$~D') + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('501 WTF'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^HELO .+?\r\n$~D') + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn('250 HELO'."\r\n"); + + $this->finishBuffer($buf); + try { + $smtp->start(); + } catch (Exception $e) { + $this->fail( + 'Starting Esmtp should fallback to HELO if needed and accept 250 response' + ); + } + } + + public function testInvalidHeloResponseCausesException() + { + //Overridden to first try EHLO + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 some.server.tld bleh\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^EHLO .+?\r\n$~D') + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('501 WTF'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^HELO .+?\r\n$~D') + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn('504 WTF'."\r\n"); + $this->finishBuffer($buf); + + try { + $this->assertFalse($smtp->isStarted(), '%s: SMTP should begin non-started'); + $smtp->start(); + $this->fail('Non 250 HELO response should raise Exception'); + } catch (Exception $e) { + $this->assertFalse($smtp->isStarted(), '%s: SMTP start() should have failed'); + } + } + + public function testDomainNameIsPlacedInEhlo() + { + /* -- RFC 2821, 4.1.4. + + The SMTP client MUST, if possible, ensure that the domain parameter + to the EHLO command is a valid principal host name (not a CNAME or MX + name) for its host. If this is not possible (e.g., when the client's + address is dynamically assigned and the client does not have an + obvious name), an address literal SHOULD be substituted for the + domain name and supplemental information provided that will assist in + identifying the client. + */ + + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 some.server.tld bleh\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("EHLO mydomain.com\r\n") + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('250 ServerName'."\r\n"); + + $this->finishBuffer($buf); + $smtp->setLocalDomain('mydomain.com'); + $smtp->start(); + } + + public function testDomainNameIsPlacedInHelo() + { + //Overridden to include ESMTP + /* -- RFC 2821, 4.1.4. + + The SMTP client MUST, if possible, ensure that the domain parameter + to the EHLO command is a valid principal host name (not a CNAME or MX + name) for its host. If this is not possible (e.g., when the client's + address is dynamically assigned and the client does not have an + obvious name), an address literal SHOULD be substituted for the + domain name and supplemental information provided that will assist in + identifying the client. + */ + + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('readLine') + ->once() + ->with(0) + ->andReturn("220 some.server.tld bleh\r\n"); + $buf->shouldReceive('write') + ->once() + ->with('~^EHLO .+?\r\n$~D') + ->andReturn(1); + $buf->shouldReceive('readLine') + ->once() + ->with(1) + ->andReturn('501 WTF'."\r\n"); + $buf->shouldReceive('write') + ->once() + ->with("HELO mydomain.com\r\n") + ->andReturn(2); + $buf->shouldReceive('readLine') + ->once() + ->with(2) + ->andReturn('250 ServerName'."\r\n"); + + $this->finishBuffer($buf); + $smtp->setLocalDomain('mydomain.com'); + $smtp->start(); + } + + public function testFluidInterface() + { + $buf = $this->getBuffer(); + $smtp = $this->getTransport($buf); + $buf->shouldReceive('setParam') + ->once() + ->with('timeout', 30); + + $ref = $smtp + ->setHost('foo') + ->setPort(25) + ->setEncryption('tls') + ->setTimeout(30) + ; + $this->assertEquals($ref, $smtp); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/FailoverTransportTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/FailoverTransportTest.php new file mode 100644 index 00000000..9f46d279 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/FailoverTransportTest.php @@ -0,0 +1,600 @@ +getMockery('Swift_Mime_SimpleMessage'); + $message2 = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState = false; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState) { + return $connectionState; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState) { + if (!$connectionState) { + $connectionState = true; + } + }); + $t1->shouldReceive('send') + ->twice() + ->with(\Mockery::anyOf($message1, $message2), \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState) { + if ($connectionState) { + return 1; + } + }); + $t2->shouldReceive('start')->never(); + $t2->shouldReceive('send')->never(); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $this->assertEquals(1, $transport->send($message1)); + $this->assertEquals(1, $transport->send($message2)); + } + + public function testMessageCanBeTriedOnNextTransportIfExceptionThrown() + { + $e = new Swift_TransportException('b0rken'); + + $message = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = false; + $connectionState2 = false; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $e) { + if ($connectionState1) { + throw $e; + } + }); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2, $e) { + if ($connectionState2) { + return 1; + } + }); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $this->assertEquals(1, $transport->send($message)); + } + + public function testZeroIsReturnedIfTransportReturnsZero() + { + $message = $this->getMockery('Swift_Mime_SimpleMessage')->shouldIgnoreMissing(); + $t1 = $this->getMockery('Swift_Transport')->shouldIgnoreMissing(); + + $connectionState = false; + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState) { + return $connectionState; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState) { + if (!$connectionState) { + $connectionState = true; + } + }); + $testCase = $this; + $t1->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState, $testCase) { + if (!$connectionState) { + $testCase->fail(); + } + + return 0; + }); + + $transport = $this->getTransport(array($t1)); + $transport->start(); + $this->assertEquals(0, $transport->send($message)); + } + + public function testTransportsWhichThrowExceptionsAreNotRetried() + { + $e = new Swift_TransportException('maur b0rken'); + + $message1 = $this->getMockery('Swift_Mime_SimpleMessage'); + $message2 = $this->getMockery('Swift_Mime_SimpleMessage'); + $message3 = $this->getMockery('Swift_Mime_SimpleMessage'); + $message4 = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = false; + $connectionState2 = false; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message1, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $e) { + if ($connectionState1) { + throw $e; + } + }); + $t1->shouldReceive('send') + ->never() + ->with($message2, \Mockery::any()); + $t1->shouldReceive('send') + ->never() + ->with($message3, \Mockery::any()); + $t1->shouldReceive('send') + ->never() + ->with($message4, \Mockery::any()); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->times(4) + ->with(\Mockery::anyOf($message1, $message2, $message3, $message4), \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2, $e) { + if ($connectionState2) { + return 1; + } + }); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $this->assertEquals(1, $transport->send($message1)); + $this->assertEquals(1, $transport->send($message2)); + $this->assertEquals(1, $transport->send($message3)); + $this->assertEquals(1, $transport->send($message4)); + } + + public function testExceptionIsThrownIfAllTransportsDie() + { + $e = new Swift_TransportException('b0rken'); + + $message = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = false; + $connectionState2 = false; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $e) { + if ($connectionState1) { + throw $e; + } + }); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2, $e) { + if ($connectionState2) { + throw $e; + } + }); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + try { + $transport->send($message); + $this->fail('All transports failed so Exception should be thrown'); + } catch (Exception $e) { + } + } + + public function testStoppingTransportStopsAllDelegates() + { + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + + $connectionState1 = true; + $connectionState2 = true; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('stop') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if ($connectionState1) { + $connectionState1 = false; + } + }); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('stop') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if ($connectionState2) { + $connectionState2 = false; + } + }); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $transport->stop(); + } + + public function testTransportShowsAsNotStartedIfAllDelegatesDead() + { + $e = new Swift_TransportException('b0rken'); + + $message = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + + $connectionState1 = false; + $connectionState2 = false; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $e) { + if ($connectionState1) { + $connectionState1 = false; + throw $e; + } + }); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2, $e) { + if ($connectionState2) { + $connectionState2 = false; + throw $e; + } + }); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $this->assertTrue($transport->isStarted()); + try { + $transport->send($message); + $this->fail('All transports failed so Exception should be thrown'); + } catch (Exception $e) { + $this->assertFalse($transport->isStarted()); + } + } + + public function testRestartingTransportRestartsDeadDelegates() + { + $e = new Swift_TransportException('b0rken'); + + $message1 = $this->getMockery('Swift_Mime_SimpleMessage'); + $message2 = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + + $connectionState1 = false; + $connectionState2 = false; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->twice() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message1, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $e) { + if ($connectionState1) { + $connectionState1 = false; + throw $e; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message2, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1) { + if ($connectionState1) { + return 10; + } + }); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->once() + ->with($message1, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2, $e) { + if ($connectionState2) { + $connectionState2 = false; + throw $e; + } + }); + $t2->shouldReceive('send') + ->never() + ->with($message2, \Mockery::any()); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $this->assertTrue($transport->isStarted()); + try { + $transport->send($message1); + $this->fail('All transports failed so Exception should be thrown'); + } catch (Exception $e) { + $this->assertFalse($transport->isStarted()); + } + //Restart and re-try + $transport->start(); + $this->assertTrue($transport->isStarted()); + $this->assertEquals(10, $transport->send($message2)); + } + + public function testFailureReferenceIsPassedToDelegates() + { + $failures = array(); + + $message = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + + $connectionState = false; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use ($connectionState) { + return $connectionState; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use ($connectionState) { + if (!$connectionState) { + $connectionState = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message, $failures) + ->andReturnUsing(function () use ($connectionState) { + if ($connectionState) { + return 1; + } + }); + + $transport = $this->getTransport(array($t1)); + $transport->start(); + $transport->send($message, $failures); + } + + public function testRegisterPluginDelegatesToLoadedTransports() + { + $plugin = $this->createPlugin(); + + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $t1->shouldReceive('registerPlugin') + ->once() + ->with($plugin); + $t2->shouldReceive('registerPlugin') + ->once() + ->with($plugin); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->registerPlugin($plugin); + } + + public function testEachDelegateIsPinged() + { + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = false; + $connectionState2 = false; + + $testCase = $this; + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('ping') + ->once() + ->andReturn(true); + + $transport = $this->getTransport(array($t1, $t2)); + $this->assertTrue($transport->isStarted()); + $this->assertTrue($transport->ping()); + } + + public function testDelegateIsKilledWhenPingFails() + { + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + + $testCase = $this; + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('ping') + ->once() + ->andReturn(false); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('ping') + ->twice() + ->andReturn(true); + + $transport = $this->getTransport(array($t1, $t2)); + $this->assertTrue($transport->ping()); + $this->assertTrue($transport->ping()); + $this->assertTrue($transport->isStarted()); + } + + public function XtestTransportShowsAsNotStartedIfAllPingFails() + { + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + + $testCase = $this; + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('ping') + ->once() + ->andReturn(false); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('ping') + ->once() + ->andReturn(false); + + $transport = $this->getTransport(array($t1, $t2)); + $this->assertFalse($transport->ping()); + $this->assertFalse($transport->isStarted()); + $this->assertFalse($transport->ping()); + } + + private function getTransport(array $transports) + { + $transport = new Swift_Transport_FailoverTransport(); + $transport->setTransports($transports); + + return $transport; + } + + private function createPlugin() + { + return $this->getMockery('Swift_Events_EventListener'); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/LoadBalancedTransportTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/LoadBalancedTransportTest.php new file mode 100644 index 00000000..e0283843 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/LoadBalancedTransportTest.php @@ -0,0 +1,838 @@ +getMockery('Swift_Mime_SimpleMessage'); + $message2 = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = false; + $connectionState2 = false; + + $testCase = $this; + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message1, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $testCase) { + if ($connectionState1) { + return 1; + } + $testCase->fail(); + }); + $t1->shouldReceive('send') + ->never() + ->with($message2, \Mockery::any()); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->once() + ->with($message2, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2, $testCase) { + if ($connectionState2) { + return 1; + } + $testCase->fail(); + }); + $t2->shouldReceive('send') + ->never() + ->with($message1, \Mockery::any()); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $this->assertEquals(1, $transport->send($message1)); + $this->assertEquals(1, $transport->send($message2)); + } + + public function testTransportsAreReusedInRotatingFashion() + { + $message1 = $this->getMockery('Swift_Mime_SimpleMessage'); + $message2 = $this->getMockery('Swift_Mime_SimpleMessage'); + $message3 = $this->getMockery('Swift_Mime_SimpleMessage'); + $message4 = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = false; + $connectionState2 = false; + + $testCase = $this; + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message1, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $testCase) { + if ($connectionState1) { + return 1; + } + $testCase->fail(); + }); + $t1->shouldReceive('send') + ->never() + ->with($message2, \Mockery::any()); + $t1->shouldReceive('send') + ->once() + ->with($message3, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $testCase) { + if ($connectionState1) { + return 1; + } + $testCase->fail(); + }); + $t1->shouldReceive('send') + ->never() + ->with($message4, \Mockery::any()); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->once() + ->with($message2, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2, $testCase) { + if ($connectionState2) { + return 1; + } + $testCase->fail(); + }); + $t2->shouldReceive('send') + ->never() + ->with($message1, \Mockery::any()); + $t2->shouldReceive('send') + ->once() + ->with($message4, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2, $testCase) { + if ($connectionState2) { + return 1; + } + $testCase->fail(); + }); + $t2->shouldReceive('send') + ->never() + ->with($message3, \Mockery::any()); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + + $this->assertEquals(1, $transport->send($message1)); + $this->assertEquals(1, $transport->send($message2)); + $this->assertEquals(1, $transport->send($message3)); + $this->assertEquals(1, $transport->send($message4)); + } + + public function testMessageCanBeTriedOnNextTransportIfExceptionThrown() + { + $e = new Swift_TransportException('b0rken'); + + $message = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = false; + $connectionState2 = false; + + $testCase = $this; + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $e, $testCase) { + if ($connectionState1) { + throw $e; + } + $testCase->fail(); + }); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2, $testCase) { + if ($connectionState2) { + return 1; + } + $testCase->fail(); + }); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $this->assertEquals(1, $transport->send($message)); + } + + public function testMessageIsTriedOnNextTransportIfZeroReturned() + { + $message = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = false; + $connectionState2 = false; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1) { + if ($connectionState1) { + return 0; + } + + return 1; + }); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2) { + if ($connectionState2) { + return 1; + } + + return 0; + }); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $this->assertEquals(1, $transport->send($message)); + } + + public function testZeroIsReturnedIfAllTransportsReturnZero() + { + $message = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = false; + $connectionState2 = false; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1) { + if ($connectionState1) { + return 0; + } + + return 1; + }); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2) { + if ($connectionState2) { + return 0; + } + + return 1; + }); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $this->assertEquals(0, $transport->send($message)); + } + + public function testTransportsWhichThrowExceptionsAreNotRetried() + { + $e = new Swift_TransportException('maur b0rken'); + + $message1 = $this->getMockery('Swift_Mime_SimpleMessage'); + $message2 = $this->getMockery('Swift_Mime_SimpleMessage'); + $message3 = $this->getMockery('Swift_Mime_SimpleMessage'); + $message4 = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = false; + $connectionState2 = false; + + $testCase = $this; + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message1, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $e, $testCase) { + if ($connectionState1) { + throw $e; + } + $testCase->fail(); + }); + $t1->shouldReceive('send') + ->never() + ->with($message2, \Mockery::any()); + $t1->shouldReceive('send') + ->never() + ->with($message3, \Mockery::any()); + $t1->shouldReceive('send') + ->never() + ->with($message4, \Mockery::any()); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->times(4) + ->with(\Mockery::anyOf($message1, $message3, $message3, $message4), \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2, $testCase) { + if ($connectionState2) { + return 1; + } + $testCase->fail(); + }); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $this->assertEquals(1, $transport->send($message1)); + $this->assertEquals(1, $transport->send($message2)); + $this->assertEquals(1, $transport->send($message3)); + $this->assertEquals(1, $transport->send($message4)); + } + + public function testExceptionIsThrownIfAllTransportsDie() + { + $e = new Swift_TransportException('b0rken'); + + $message = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = false; + $connectionState2 = false; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $e) { + if ($connectionState1) { + throw $e; + } + }); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2, $e) { + if ($connectionState2) { + throw $e; + } + }); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + try { + $transport->send($message); + $this->fail('All transports failed so Exception should be thrown'); + } catch (Exception $e) { + } + } + + public function testStoppingTransportStopsAllDelegates() + { + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = true; + $connectionState2 = true; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('stop') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if ($connectionState1) { + $connectionState1 = false; + } + }); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('stop') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if ($connectionState2) { + $connectionState2 = false; + } + }); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $transport->stop(); + } + + public function testTransportShowsAsNotStartedIfAllDelegatesDead() + { + $e = new Swift_TransportException('b0rken'); + + $message = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = false; + $connectionState2 = false; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $e) { + if ($connectionState1) { + throw $e; + } + }); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->once() + ->with($message, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2, $e) { + if ($connectionState2) { + throw $e; + } + }); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $this->assertTrue($transport->isStarted()); + try { + $transport->send($message); + $this->fail('All transports failed so Exception should be thrown'); + } catch (Exception $e) { + $this->assertFalse($transport->isStarted()); + } + } + + public function testRestartingTransportRestartsDeadDelegates() + { + $e = new Swift_TransportException('b0rken'); + + $message1 = $this->getMockery('Swift_Mime_SimpleMessage'); + $message2 = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + $connectionState1 = false; + $connectionState2 = false; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('start') + ->twice() + ->andReturnUsing(function () use (&$connectionState1) { + if (!$connectionState1) { + $connectionState1 = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message1, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $e) { + if ($connectionState1) { + $connectionState1 = false; + throw $e; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message2, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState1, $e) { + if ($connectionState1) { + return 10; + } + }); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState2) { + if (!$connectionState2) { + $connectionState2 = true; + } + }); + $t2->shouldReceive('send') + ->once() + ->with($message1, \Mockery::any()) + ->andReturnUsing(function () use (&$connectionState2, $e) { + if ($connectionState2) { + throw $e; + } + }); + $t2->shouldReceive('send') + ->never() + ->with($message2, \Mockery::any()); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->start(); + $this->assertTrue($transport->isStarted()); + try { + $transport->send($message1); + $this->fail('All transports failed so Exception should be thrown'); + } catch (Exception $e) { + $this->assertFalse($transport->isStarted()); + } + //Restart and re-try + $transport->start(); + $this->assertTrue($transport->isStarted()); + $this->assertEquals(10, $transport->send($message2)); + } + + public function testFailureReferenceIsPassedToDelegates() + { + $failures = array(); + $testCase = $this; + + $message = $this->getMockery('Swift_Mime_SimpleMessage'); + $t1 = $this->getMockery('Swift_Transport'); + $connectionState = false; + + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState) { + return $connectionState; + }); + $t1->shouldReceive('start') + ->once() + ->andReturnUsing(function () use (&$connectionState) { + if (!$connectionState) { + $connectionState = true; + } + }); + $t1->shouldReceive('send') + ->once() + ->with($message, \Mockery::on(function (&$var) use (&$failures, $testCase) { + return $testCase->varsAreReferences($var, $failures); + })) + ->andReturnUsing(function () use (&$connectionState) { + if ($connectionState) { + return 1; + } + }); + + $transport = $this->getTransport(array($t1)); + $transport->start(); + $transport->send($message, $failures); + } + + public function testRegisterPluginDelegatesToLoadedTransports() + { + $plugin = $this->createPlugin(); + + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + + $t1->shouldReceive('registerPlugin') + ->once() + ->with($plugin); + $t2->shouldReceive('registerPlugin') + ->once() + ->with($plugin); + + $transport = $this->getTransport(array($t1, $t2)); + $transport->registerPlugin($plugin); + } + + public function testEachDelegateIsPinged() + { + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + + $testCase = $this; + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('ping') + ->once() + ->andReturn(true); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('ping') + ->once() + ->andReturn(true); + + $transport = $this->getTransport(array($t1, $t2)); + $this->assertTrue($transport->isStarted()); + $this->assertTrue($transport->ping()); + } + + public function testDelegateIsKilledWhenPingFails() + { + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + + $testCase = $this; + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('ping') + ->twice() + ->andReturn(true); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('ping') + ->once() + ->andReturn(false); + + $transport = $this->getTransport(array($t1, $t2)); + $this->assertTrue($transport->ping()); + $this->assertTrue($transport->ping()); + $this->assertTrue($transport->isStarted()); + } + + public function testTransportShowsAsNotStartedIfAllPingFails() + { + $t1 = $this->getMockery('Swift_Transport'); + $t2 = $this->getMockery('Swift_Transport'); + + $testCase = $this; + $t1->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState1) { + return $connectionState1; + }); + $t1->shouldReceive('ping') + ->once() + ->andReturn(false); + + $t2->shouldReceive('isStarted') + ->zeroOrMoreTimes() + ->andReturnUsing(function () use (&$connectionState2) { + return $connectionState2; + }); + $t2->shouldReceive('ping') + ->once() + ->andReturn(false); + + $transport = $this->getTransport(array($t1, $t2)); + $this->assertFalse($transport->ping()); + $this->assertFalse($transport->isStarted()); + $this->assertFalse($transport->ping()); + } + + /** + * Adapted from Yay_Matchers_ReferenceMatcher. + */ + public function varsAreReferences(&$ref1, &$ref2) + { + if (is_object($ref2)) { + return $ref1 === $ref2; + } + if ($ref1 !== $ref2) { + return false; + } + + $copy = $ref2; + $randomString = uniqid('yay', true); + $ref2 = $randomString; + $isRef = ($ref1 === $ref2); + $ref2 = $copy; + + return $isRef; + } + + private function getTransport(array $transports) + { + $transport = new Swift_Transport_LoadBalancedTransport(); + $transport->setTransports($transports); + + return $transport; + } + + private function createPlugin() + { + return $this->getMockery('Swift_Events_EventListener'); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/SendmailTransportTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/SendmailTransportTest.php new file mode 100644 index 00000000..034e5a08 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/SendmailTransportTest.php @@ -0,0 +1,150 @@ +createEventDispatcher(); + } + $transport = new Swift_Transport_SendmailTransport($buf, $dispatcher, 'example.org'); + $transport->setCommand($command); + + return $transport; + } + + protected function getSendmail($buf, $dispatcher = null) + { + if (!$dispatcher) { + $dispatcher = $this->createEventDispatcher(); + } + + return new Swift_Transport_SendmailTransport($buf, $dispatcher); + } + + public function testCommandCanBeSetAndFetched() + { + $buf = $this->getBuffer(); + $sendmail = $this->getSendmail($buf); + + $sendmail->setCommand('/usr/sbin/sendmail -bs'); + $this->assertEquals('/usr/sbin/sendmail -bs', $sendmail->getCommand()); + $sendmail->setCommand('/usr/sbin/sendmail -oi -t'); + $this->assertEquals('/usr/sbin/sendmail -oi -t', $sendmail->getCommand()); + } + + public function testSendingMessageIn_t_ModeUsesSimplePipe() + { + $buf = $this->getBuffer(); + $sendmail = $this->getSendmail($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('foo@bar' => 'Foobar', 'zip@button' => 'Zippy')); + $message->shouldReceive('toByteStream') + ->once() + ->with($buf); + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('terminate') + ->once(); + $buf->shouldReceive('setWriteTranslations') + ->once() + ->with(array("\r\n" => "\n", "\n." => "\n..")); + $buf->shouldReceive('setWriteTranslations') + ->once() + ->with(array()); + + $sendmail->setCommand('/usr/sbin/sendmail -t'); + $this->assertEquals(2, $sendmail->send($message)); + } + + public function testSendingIn_t_ModeWith_i_FlagDoesntEscapeDot() + { + $buf = $this->getBuffer(); + $sendmail = $this->getSendmail($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('foo@bar' => 'Foobar', 'zip@button' => 'Zippy')); + $message->shouldReceive('toByteStream') + ->once() + ->with($buf); + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('terminate') + ->once(); + $buf->shouldReceive('setWriteTranslations') + ->once() + ->with(array("\r\n" => "\n")); + $buf->shouldReceive('setWriteTranslations') + ->once() + ->with(array()); + + $sendmail->setCommand('/usr/sbin/sendmail -i -t'); + $this->assertEquals(2, $sendmail->send($message)); + } + + public function testSendingInTModeWith_oi_FlagDoesntEscapeDot() + { + $buf = $this->getBuffer(); + $sendmail = $this->getSendmail($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('foo@bar' => 'Foobar', 'zip@button' => 'Zippy')); + $message->shouldReceive('toByteStream') + ->once() + ->with($buf); + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('terminate') + ->once(); + $buf->shouldReceive('setWriteTranslations') + ->once() + ->with(array("\r\n" => "\n")); + $buf->shouldReceive('setWriteTranslations') + ->once() + ->with(array()); + + $sendmail->setCommand('/usr/sbin/sendmail -oi -t'); + $this->assertEquals(2, $sendmail->send($message)); + } + + public function testSendingMessageRegeneratesId() + { + $buf = $this->getBuffer(); + $sendmail = $this->getSendmail($buf); + $message = $this->createMessage(); + + $message->shouldReceive('getTo') + ->zeroOrMoreTimes() + ->andReturn(array('foo@bar' => 'Foobar', 'zip@button' => 'Zippy')); + $message->shouldReceive('generateId'); + $buf->shouldReceive('initialize') + ->once(); + $buf->shouldReceive('terminate') + ->once(); + $buf->shouldReceive('setWriteTranslations') + ->once() + ->with(array("\r\n" => "\n", "\n." => "\n..")); + $buf->shouldReceive('setWriteTranslations') + ->once() + ->with(array()); + + $sendmail->setCommand('/usr/sbin/sendmail -t'); + $this->assertEquals(2, $sendmail->send($message)); + } + + public function testFluidInterface() + { + $buf = $this->getBuffer(); + $sendmail = $this->getTransport($buf); + + $ref = $sendmail->setCommand('/foo'); + $this->assertEquals($ref, $sendmail); + } +} diff --git a/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/StreamBufferTest.php b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/StreamBufferTest.php new file mode 100644 index 00000000..a9c45099 --- /dev/null +++ b/lib/composer/vendor/swiftmailer/swiftmailer/tests/unit/Swift/Transport/StreamBufferTest.php @@ -0,0 +1,43 @@ +createFactory(); + $factory->expects($this->once()) + ->method('createFilter') + ->with('a', 'b') + ->will($this->returnCallback(array($this, 'createFilter'))); + + $buffer = $this->createBuffer($factory); + $buffer->setWriteTranslations(array('a' => 'b')); + } + + public function testOverridingTranslationsOnlyAddsNeededFilters() + { + $factory = $this->createFactory(); + $factory->expects($this->exactly(2)) + ->method('createFilter') + ->will($this->returnCallback(array($this, 'createFilter'))); + + $buffer = $this->createBuffer($factory); + $buffer->setWriteTranslations(array('a' => 'b')); + $buffer->setWriteTranslations(array('x' => 'y', 'a' => 'b')); + } + + private function createBuffer($replacementFactory) + { + return new Swift_Transport_StreamBuffer($replacementFactory); + } + + private function createFactory() + { + return $this->getMockBuilder('Swift_ReplacementFilterFactory')->getMock(); + } + + public function createFilter() + { + return $this->getMockBuilder('Swift_StreamFilter')->getMock(); + } +} diff --git a/migrations/list.php b/migrations/list.php index 89ce6d4e..c21c576b 100644 --- a/migrations/list.php +++ b/migrations/list.php @@ -1,5 +1,6 @@ Load("name = ?", array('Email: Mode')); + if(!empty($setting->id)){ + $setting->description = 'Require submitting a photo using web cam when marking attendance'; + $setting->meta = '["value", {"label":"Value","type":"select","source":[["SMTP","SMTP"],["Swift SMTP","Swift SMTP"],["PHP Mailer","PHP Mailer"],["SES","Amazon SES"]]}]'; + $setting->Save(); + } + + return true; + } + + public function down(){ + return true; + } + +} + diff --git a/server.includes.inc.php b/server.includes.inc.php index 7fc3d787..5b2ce583 100644 --- a/server.includes.inc.php +++ b/server.includes.inc.php @@ -135,6 +135,8 @@ if ($emailEnabled == "1") { $emailSender = new \Classes\Email\SNSEmailSender($settingsManager); } elseif ($emailMode == "PHP Mailer") { $emailSender = new \Classes\Email\PHPMailer($settingsManager); + } elseif ($emailMode == "Swift SMTP") { + $emailSender = new \Classes\Email\SwiftMailer($settingsManager); } } diff --git a/src/Classes/Email/EmailSender.php b/src/Classes/Email/EmailSender.php index b459f8f5..974941bf 100644 --- a/src/Classes/Email/EmailSender.php +++ b/src/Classes/Email/EmailSender.php @@ -84,7 +84,7 @@ abstract class EmailSender $body = str_replace("#_".$k."_#", $v, $body); } - $fromEmail = APP_NAME." <".$this->settings->getSetting("Email: Email From").">"; + $fromEmail = $this->settings->getSetting("Email: Email From"); //Convert to an html email $emailBody = file_get_contents(APP_BASE_PATH.'/templates/email/emailBody.html'); @@ -110,7 +110,7 @@ abstract class EmailSender $emailBody = str_replace("#_".$k."_#", $v, $emailBody); } - return $this->sendMail($subject, $emailBody, $toEmail, $fromEmail, $user->email, $ccList, $bccList); + return $this->sendMail($subject, $emailBody, $toEmail, $fromEmail, $user->email, $ccList, $bccList, APP_NAME); } public function sendEmailWithoutWrap($subject, $toEmail, $template, $params, $ccList = array(), $bccList = array()) @@ -156,7 +156,8 @@ abstract class EmailSender $fromEmail, $replyToEmail = null, $ccList = array(), - $bccList = array() + $bccList = array(), + $fromName = null ); public function sendResetPasswordEmail($emailOrUserId) diff --git a/src/Classes/Email/PHPMailer.php b/src/Classes/Email/PHPMailer.php index 5b3dc507..e6deb4b9 100644 --- a/src/Classes/Email/PHPMailer.php +++ b/src/Classes/Email/PHPMailer.php @@ -25,10 +25,16 @@ class PHPMailer extends EmailSender $fromEmail, $replyToEmail = null, $ccList = array(), - $bccList = array() + $bccList = array(), + $fromName = null ) { try { + + if ($fromName) { + $fromEmail = $fromName." <".$fromEmail.">"; + } + if (empty($replyToEmail)) { $replyToEmail = $fromEmail; } @@ -46,13 +52,8 @@ class PHPMailer extends EmailSender } $headers .= 'ReplyTo: ' . $replyToEmail . "\r\n"; $headers .= 'Ice-Mailer: PHP/' . phpversion(); - - // Mail it - $res = mail($toEmail, $subject, $body, $headers); - - LogManager::getInstance()->info("PHP mailer result : " . $res); - - return $res; + + return mail($toEmail, $subject, $body, $headers); } catch (\Exception $e) { LogManager::getInstance()->error("Error sending email:" . $e->getMessage()); return false; diff --git a/src/Classes/Email/SMTPEmailSender.php b/src/Classes/Email/SMTPEmailSender.php index 0336be3f..07c635ab 100644 --- a/src/Classes/Email/SMTPEmailSender.php +++ b/src/Classes/Email/SMTPEmailSender.php @@ -25,7 +25,8 @@ class SMTPEmailSender extends EmailSender $fromEmail, $replyToEmail = null, $ccList = array(), - $bccList = array() + $bccList = array(), + $fromName = '' ) { try { @@ -76,9 +77,10 @@ class SMTPEmailSender extends EmailSender $mail = $smtp->send($toEmail, $headers, $body); if (\PEAR::isError($mail)) { LogManager::getInstance()->info("SMTP Error Response:" . $mail->getMessage()); + return false; } - return $mail; + return true; } catch (\Exception $e) { LogManager::getInstance()->error("Error sending email:" . $e->getMessage()); return false; diff --git a/src/Classes/Email/SNSEmailSender.php b/src/Classes/Email/SNSEmailSender.php index 3f52bb11..f97f0840 100644 --- a/src/Classes/Email/SNSEmailSender.php +++ b/src/Classes/Email/SNSEmailSender.php @@ -31,10 +31,15 @@ class SNSEmailSender extends EmailSender $fromEmail, $replyToEmail = null, $ccList = array(), - $bccList = array() + $bccList = array(), + $fromName = null ) { try { + if ($fromName) { + $fromEmail = $fromName." <".$fromEmail.">"; + } + if (empty($replyToEmail)) { $replyToEmail = $fromEmail; } @@ -57,7 +62,6 @@ class SNSEmailSender extends EmailSender ) ); - //$response = $this->ses->sendEmail($fromEmail, $toArray, $message); $response = $this->ses->sendEmail( array( 'Source' => $fromEmail, @@ -70,7 +74,7 @@ class SNSEmailSender extends EmailSender LogManager::getInstance()->info("SES Response:" . print_r($response, true)); - return $response; + return true; } catch (\Exception $e) { LogManager::getInstance()->error("Error sending email:" . $e->getMessage()); return false; diff --git a/src/Classes/Email/SwiftMailer.php b/src/Classes/Email/SwiftMailer.php new file mode 100644 index 00000000..7ae0b111 --- /dev/null +++ b/src/Classes/Email/SwiftMailer.php @@ -0,0 +1,64 @@ +info("Sending email to: " . $toEmail . "/ from: " . $fromEmail); + + $host = $this->settings->getSetting("Email: SMTP Host"); + $username = $this->settings->getSetting("Email: SMTP User"); + $password = $this->settings->getSetting("Email: SMTP Password"); + $port = $this->settings->getSetting("Email: SMTP Port"); + + if (empty($port)) { + $port = '25'; + } + $transport = new \Swift_SmtpTransport($host, $port); + $mail = new \Swift_Message(); + + if ($this->settings->getSetting("Email: SMTP Authentication Required") === "1") { + $transport->setUsername($username); + $transport->setPassword($password); + } + + $mail->addFrom($fromEmail, $fromName); + $mail->addReplyTo($replyToEmail); + $mail->addTo($toEmail); + $mail->setSubject($subject); + $mail->setCc($ccList); + $mail->setBcc($bccList); + $mail->setBody($body); + + $mailer = new \Swift_Mailer($transport); + return $mailer->send($mail); + + } catch (\Exception $e) { + LogManager::getInstance()->error("Error sending email:" . $e->getMessage()); + return false; + } + } +} diff --git a/src/Users/Admin/Api/UsersActionManager.php b/src/Users/Admin/Api/UsersActionManager.php index 1c13cddc..a53f9444 100644 --- a/src/Users/Admin/Api/UsersActionManager.php +++ b/src/Users/Admin/Api/UsersActionManager.php @@ -98,16 +98,17 @@ class UsersActionManager extends SubActionManager $ok = $user->Save(); if (!$ok) { LogManager::getInstance()->info($user->ErrorMsg()."|".json_encode($user)); - return new IceResponse(IceResponse::ERROR, "Error occured while saving the user"); + return new IceResponse(IceResponse::ERROR, "Error occurred while saving the user"); } $user->password = ""; $user = $this->baseService->cleanUpAdoDB($user); + $mailResponse = false; if (!empty($this->emailSender)) { $usersEmailSender = new UsersEmailSender($this->emailSender, $this); - $usersEmailSender->sendWelcomeUserEmail($user, $password, $employee); + $mailResponse = $usersEmailSender->sendWelcomeUserEmail($user, $password, $employee); } - return new IceResponse(IceResponse::SUCCESS, $user); + return new IceResponse(IceResponse::SUCCESS, [$user, $mailResponse]); } return new IceResponse(IceResponse::ERROR, "Not Allowed"); } diff --git a/src/Users/Admin/Api/UsersEmailSender.php b/src/Users/Admin/Api/UsersEmailSender.php index df63e8b7..4a738f9c 100644 --- a/src/Users/Admin/Api/UsersEmailSender.php +++ b/src/Users/Admin/Api/UsersEmailSender.php @@ -42,10 +42,12 @@ class UsersEmailSender if (!empty($emailTo)) { if (!empty($this->emailSender)) { LogManager::getInstance()->info("[sendWelcomeUserEmail] sending email to $emailTo : ".$email); - $this->emailSender->sendEmail("Your IceHrm account is ready", $emailTo, $email, $params); + return $this->emailSender->sendEmail("Your IceHrm account is ready", $emailTo, $email, $params); } } else { LogManager::getInstance()->info("[sendWelcomeUserEmail] email is empty"); } + + return false; } } From 22f75d6e514327bd8842d29907083dfefbb9dd27 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 26 Nov 2017 19:28:12 +0100 Subject: [PATCH 14/21] Fix issue: special chars in db password --- server.includes.inc.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server.includes.inc.php b/server.includes.inc.php index 5b2ce583..96ff8bc6 100644 --- a/server.includes.inc.php +++ b/server.includes.inc.php @@ -24,7 +24,9 @@ if (defined("MODULE_PATH")) { $user = \Utils\SessionUtils::getSessionObject('user'); -$dbLocal = NewADOConnection(APP_CON_STR); +$dbLocal = NewADOConnection('mysqli'); +$res = $dbLocal->Connect(APP_HOST, APP_USERNAME, APP_PASSWORD, APP_DB); + \Model\File::SetDatabaseAdapter($dbLocal); \Model\Setting::SetDatabaseAdapter($dbLocal); From a6d2abcb45c3a8722841fb325d8dcd0ad1ac8029 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 26 Nov 2017 19:44:41 +0100 Subject: [PATCH 15/21] Adding edit button to employee list --- admin/employees/lib.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/employees/lib.js b/admin/employees/lib.js index 358772f3..8760d888 100644 --- a/admin/employees/lib.js +++ b/admin/employees/lib.js @@ -252,7 +252,7 @@ EmployeeAdapter.method('getFilters', function() { }); EmployeeAdapter.method('getActionButtonsHtml', function(id) { - var html = '
'; + var html = '
'; html = html.replace(/_id_/g,id); html = html.replace(/_BASE_/g,this.baseUrl); return html; From af5569dc32c678104763e7126d722bc9fcd09cf0 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 26 Nov 2017 20:00:21 +0100 Subject: [PATCH 16/21] Remove delete function from employee filed names, remove default custom fields --- admin/fieldnames/index.php | 11 ++++++----- scripts/icehrm_master_data.sql | 12 ------------ 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/admin/fieldnames/index.php b/admin/fieldnames/index.php index 3f648a9b..92ae663d 100644 --- a/admin/fieldnames/index.php +++ b/admin/fieldnames/index.php @@ -1,10 +1,10 @@ -
- + - +
@@ -44,6 +44,7 @@ var modJsList = new Array(); modJsList['tabEmployeeFieldName'] = new FieldNameAdapter('FieldNameMapping','EmployeeFieldName',{"type":"Employee"}); modJsList['tabEmployeeFieldName'].setRemoteTable(true); +modJsList['tabEmployeeFieldName'].setShowDelete(false); modJsList['tabEmployeeFieldName'].setShowAddNew(false); modJsList['tabEmployeeCustomField'] = new CustomFieldAdapter('CustomField','EmployeeCustomField',{"type":"Employee"},"display_order desc"); @@ -54,4 +55,4 @@ modJsList['tabEmployeeCustomField'].setTableType("Employee"); var modJs = modJsList['tabEmployeeFieldName']; - + diff --git a/scripts/icehrm_master_data.sql b/scripts/icehrm_master_data.sql index 1a053f67..0b35e1b3 100644 --- a/scripts/icehrm_master_data.sql +++ b/scripts/icehrm_master_data.sql @@ -1270,18 +1270,6 @@ INSERT INTO `FieldNameMappings` (`type`, `name`, `textOrig`, `textMapped`, `disp ('Employee', 'notes', 'Notes', 'Notes', 'Form'); -INSERT INTO `CustomFields` (`type`, `name`, `data`,`display`) VALUES - ('Employee', 'custom1', '', 'Hidden'), - ('Employee', 'custom2', '', 'Hidden'), - ('Employee', 'custom3', '', 'Hidden'), - ('Employee', 'custom4', '', 'Hidden'), - ('Employee', 'custom5', '', 'Hidden'), - ('Employee', 'custom6', '', 'Hidden'), - ('Employee', 'custom7', '', 'Hidden'), - ('Employee', 'custom8', '', 'Hidden'), - ('Employee', 'custom9', '', 'Hidden'), - ('Employee', 'custom10', '', 'Hidden'); - INSERT INTO `ImmigrationStatus` VALUES (1,'Citizen'), (2,'Permanent Resident'), From 6e748327982dd1deb5bfb91aa65653bfb408684e Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 26 Nov 2017 20:16:45 +0100 Subject: [PATCH 17/21] Fix php list syntax issue --- src/Attendance/Admin/Api/AttendanceAdminManager.php | 2 +- src/Classes/RestEndPoint.php | 2 +- src/Employees/Admin/Api/EmployeesAdminManager.php | 2 +- src/Employees/Rest/EmployeeRestEndPoint.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Attendance/Admin/Api/AttendanceAdminManager.php b/src/Attendance/Admin/Api/AttendanceAdminManager.php index 42f0c178..2bfe2d86 100644 --- a/src/Attendance/Admin/Api/AttendanceAdminManager.php +++ b/src/Attendance/Admin/Api/AttendanceAdminManager.php @@ -36,7 +36,7 @@ class AttendanceAdminManager extends AbstractModuleManager \Classes\Macaw::get(REST_API_PATH.'attendance', function ($pathParams) { $restEndPoint = new AttendanceRestEndPoint(); - $restEndPoint->process('list', $pathParams); + $restEndPoint->process('listAll', $pathParams); }); \Classes\Macaw::get(REST_API_PATH.'employee/(:num)/attendance', function ($pathParams) { diff --git a/src/Classes/RestEndPoint.php b/src/Classes/RestEndPoint.php index e10a68d9..e25b21b4 100644 --- a/src/Classes/RestEndPoint.php +++ b/src/Classes/RestEndPoint.php @@ -135,7 +135,7 @@ class RestEndPoint return $obj; } - public function list(User $user) + public function listAll(User $user) { return new IceResponse(IceResponse::ERROR, "Method not Implemented", 404); } diff --git a/src/Employees/Admin/Api/EmployeesAdminManager.php b/src/Employees/Admin/Api/EmployeesAdminManager.php index 1e1dc95f..0dc87e88 100644 --- a/src/Employees/Admin/Api/EmployeesAdminManager.php +++ b/src/Employees/Admin/Api/EmployeesAdminManager.php @@ -38,7 +38,7 @@ class EmployeesAdminManager extends AbstractModuleManager \Classes\Macaw::get(REST_API_PATH.'employees', function () { $empRestEndPoint = new EmployeeRestEndPoint(); - $empRestEndPoint->process('list'); + $empRestEndPoint->process('listAll'); }); \Classes\Macaw::post(REST_API_PATH.'employees', function () { diff --git a/src/Employees/Rest/EmployeeRestEndPoint.php b/src/Employees/Rest/EmployeeRestEndPoint.php index 891b578a..7f316693 100644 --- a/src/Employees/Rest/EmployeeRestEndPoint.php +++ b/src/Employees/Rest/EmployeeRestEndPoint.php @@ -20,7 +20,7 @@ class EmployeeRestEndPoint extends RestEndPoint return $obj; } - public function list(User $user) + public function listAll(User $user) { $query = new DataQuery('Employee'); From 1ddf6ffbb6852291e5dd6569dddfb29afd82b252 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 26 Nov 2017 20:47:39 +0100 Subject: [PATCH 18/21] Fix issue: custom fields not getting saved in mysql v5.7 --- src/Classes/CustomFieldManager.php | 12 +++++++++--- src/Model/BaseModel.php | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Classes/CustomFieldManager.php b/src/Classes/CustomFieldManager.php index b68463c3..21b879cb 100644 --- a/src/Classes/CustomFieldManager.php +++ b/src/Classes/CustomFieldManager.php @@ -9,6 +9,7 @@ namespace Classes; use Metadata\Common\Model\CustomFieldValue; +use Utils\LogManager; class CustomFieldManager { @@ -28,12 +29,17 @@ class CustomFieldManager $customFieldValue->name = $name; $customFieldValue->object_id = $id; $customFieldValue->type = $type; - $customFieldValue->created = date("Y-md-d H:i:s"); + $customFieldValue->created = date("Y-m-d H:i:s"); } $customFieldValue->value = $value; - $customFieldValue->updated = date("Y-md-d H:i:s"); - $customFieldValue->Save(); + $customFieldValue->updated = date("Y-m-d H:i:s"); + $ok = $customFieldValue->Save(); + if (!$ok) { + LogManager::getInstance()->error("Error saving custom field: " . $customFieldValue->ErrorMsg()); + return false; + } + return true; } public function getCustomFields($type, $id) diff --git a/src/Model/BaseModel.php b/src/Model/BaseModel.php index f5b168ad..b234bdf2 100644 --- a/src/Model/BaseModel.php +++ b/src/Model/BaseModel.php @@ -154,7 +154,7 @@ class BaseModel extends \ADOdb_Active_Record continue; } - $keys[$k] = $k; + $keys[$k] = $v; } return $keys; From 4a07ca07e8a327d0cded6ceb9c07a986cc0d9f63 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 26 Nov 2017 20:56:12 +0100 Subject: [PATCH 19/21] Remove table and form option from employee custom fields --- admin/fieldnames/lib.js | 86 ++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/admin/fieldnames/lib.js b/admin/fieldnames/lib.js index 1d25731a..7c918466 100644 --- a/admin/fieldnames/lib.js +++ b/admin/fieldnames/lib.js @@ -8,7 +8,7 @@ */ function FieldNameAdapter(endPoint,tab,filter,orderBy) { - this.initAdapter(endPoint,tab,filter,orderBy); + this.initAdapter(endPoint,tab,filter,orderBy); } FieldNameAdapter.inherits(AdapterBase); @@ -17,32 +17,32 @@ FieldNameAdapter.inherits(AdapterBase); FieldNameAdapter.method('getDataMapping', function() { return [ - "id", - "name", - "textOrig", - "textMapped", - "display" + "id", + "name", + "textOrig", + "textMapped", + "display" ]; }); FieldNameAdapter.method('getHeaders', function() { return [ - { "sTitle": "ID" ,"bVisible":false}, - { "sTitle": "Name" }, - { "sTitle": "Original Text"}, - { "sTitle": "Mapped Text"}, - { "sTitle": "Display Status"} + { "sTitle": "ID" ,"bVisible":false}, + { "sTitle": "Name" }, + { "sTitle": "Original Text"}, + { "sTitle": "Mapped Text"}, + { "sTitle": "Display Status"} ]; }); FieldNameAdapter.method('getFormFields', function() { return [ - [ "id", {"label":"ID","type":"hidden"}], - [ "type", {"label":"Type","type":"placeholder","validation":""}], - [ "name", {"label":"Name","type":"placeholder","validation":""}], - [ "textOrig", {"label":"Original Text","type":"placeholder","validation":""}], - [ "textMapped", {"label":"Mapped Text","type":"text","validation":""}], - [ "display", {"label":"Display Status","type":"select","source":[["Form","Form"],["Table and Form","Table and Form"],["Hidden","Hidden"]]}] + [ "id", {"label":"ID","type":"hidden"}], + [ "type", {"label":"Type","type":"placeholder","validation":""}], + [ "name", {"label":"Name","type":"placeholder","validation":""}], + [ "textOrig", {"label":"Original Text","type":"placeholder","validation":""}], + [ "textMapped", {"label":"Mapped Text","type":"text","validation":""}], + [ "display", {"label":"Display Status","type":"select","source":[["Form","Show"],["Hidden","Hidden"]]}] ]; }); @@ -51,7 +51,7 @@ FieldNameAdapter.method('getFormFields', function() { */ function CustomFieldAdapter(endPoint,tab,filter,orderBy) { - this.initAdapter(endPoint,tab,filter,orderBy); + this.initAdapter(endPoint,tab,filter,orderBy); this.tableType = ""; } @@ -61,41 +61,41 @@ CustomFieldAdapter.inherits(AdapterBase); CustomFieldAdapter.method('getDataMapping', function() { return [ - "id", - "name", - "display", - "display_order" + "id", + "name", + "display", + "display_order" ]; }); CustomFieldAdapter.method('getHeaders', function() { return [ - { "sTitle": "ID" ,"bVisible":false}, - { "sTitle": "Name" }, - { "sTitle": "Display Status"}, - { "sTitle": "Priority"} + { "sTitle": "ID" ,"bVisible":false}, + { "sTitle": "Name" }, + { "sTitle": "Display Status"}, + { "sTitle": "Priority"} ]; }); CustomFieldAdapter.method('getFormFields', function() { return [ - [ "id", {"label":"ID","type":"hidden"}], - //[ "type", {"label":"Type","type":"placeholder","validation":""}], - [ "name", {"label":"Name","type":"text","validation":""}], - [ "display", {"label":"Display Status","type":"select","source":[["Form","Show"],["Hidden","Hidden"]]}], - [ "field_type", {"label":"Field Type","type":"select","source":[["text","Text Field"],["textarea","Text Area"],["select","Select"],["select2","Select2"],["select2multi","Multi Select"],["fileupload","File Upload"],["date","Date"],["datetime","Date Time"],["time","Time"]]}], - [ "field_label", {"label":"Field Label","type":"text","validation":""}], - [ "field_validation", {"label":"Validation","type":"select","validation":"none","sort":"none","source":[["","Required"],["none","None"],["number","Number"],["numberOrEmpty","Number or Empty"],["float","Decimal"],["email","Email"],["emailOrEmpty","Email or Empty"]]}], - [ "field_options", {"label":"Field Options","type":"datagroup", - "form":[ - [ "label", {"label":"Label","type":"text","validation":""}], - [ "value", {"label":"Value","type":"text","validation":"none"}] - ], - "html":'
#_delete_##_edit_##_label_#:#_value_#
', - "validation":"none" - }], - [ "display_order", {"label":"Priority","type":"text","validation":"number"}], - [ "display_section", {"label":"Display Section","type":"text","validation":""}] + [ "id", {"label":"ID","type":"hidden"}], + //[ "type", {"label":"Type","type":"placeholder","validation":""}], + [ "name", {"label":"Name","type":"text","validation":""}], + [ "display", {"label":"Display Status","type":"select","source":[["Form","Show"],["Hidden","Hidden"]]}], + [ "field_type", {"label":"Field Type","type":"select","source":[["text","Text Field"],["textarea","Text Area"],["select","Select"],["select2","Select2"],["select2multi","Multi Select"],["fileupload","File Upload"],["date","Date"],["datetime","Date Time"],["time","Time"]]}], + [ "field_label", {"label":"Field Label","type":"text","validation":""}], + [ "field_validation", {"label":"Validation","type":"select","validation":"none","sort":"none","source":[["","Required"],["none","None"],["number","Number"],["numberOrEmpty","Number or Empty"],["float","Decimal"],["email","Email"],["emailOrEmpty","Email or Empty"]]}], + [ "field_options", {"label":"Field Options","type":"datagroup", + "form":[ + [ "label", {"label":"Label","type":"text","validation":""}], + [ "value", {"label":"Value","type":"text","validation":"none"}] + ], + "html":'
#_delete_##_edit_##_label_#:#_value_#
', + "validation":"none" + }], + [ "display_order", {"label":"Priority","type":"text","validation":"number"}], + [ "display_section", {"label":"Display Section","type":"text","validation":""}] ]; }); From cf010ceb0f3d7c76fa6760237ed22a4ad82f3b32 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 26 Nov 2017 21:01:31 +0100 Subject: [PATCH 20/21] Change approver filed empty label to None --- admin/employees/lib.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/admin/employees/lib.js b/admin/employees/lib.js index 8760d888..78640dd7 100644 --- a/admin/employees/lib.js +++ b/admin/employees/lib.js @@ -197,9 +197,9 @@ EmployeeAdapter.method('getFormFields', function() { [ "department", {"label":"Department","type":"select2","remote-source":["CompanyStructure","id","title"]}], [ "supervisor", {"label":"Direct Supervisor","type":"select2","allow-null":true,"remote-source":["Employee","id","first_name+last_name"]}], [ "indirect_supervisors", {"label":"Indirect Supervisors","type":"select2multi","allow-null":true,"remote-source":["Employee","id","first_name+last_name"]}], - [ "approver1", {"label":"First Level Approver","type":"select2","allow-null":true,"remote-source":["Employee","id","first_name+last_name"]}], - [ "approver2", {"label":"Second Level Approver","type":"select2","allow-null":true,"remote-source":["Employee","id","first_name+last_name"]}], - [ "approver3", {"label":"Third Level Approver","type":"select2","allow-null":true,"remote-source":["Employee","id","first_name+last_name"]}], + [ "approver1", {"label":"First Level Approver","type":"select2","allow-null":true,"null-label":"None","remote-source":["Employee","id","first_name+last_name"]}], + [ "approver2", {"label":"Second Level Approver","type":"select2","allow-null":true,"null-label":"None","remote-source":["Employee","id","first_name+last_name"]}], + [ "approver3", {"label":"Third Level Approver","type":"select2","allow-null":true,"null-label":"None","remote-source":["Employee","id","first_name+last_name"]}], [ "notes", {"label":"Notes","type":"datagroup", "form":[ [ "note", {"label":"Note","type":"textarea","validation":""}] From 359e3f83823e98730c37d6781875e7fcabe2e5b3 Mon Sep 17 00:00:00 2001 From: gamonoid Date: Sun, 26 Nov 2017 21:40:14 +0100 Subject: [PATCH 21/21] Update release notes --- config.base.php | 8 ++++---- release.md | 13 +++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/config.base.php b/config.base.php index 029f3239..573b472d 100644 --- a/config.base.php +++ b/config.base.php @@ -13,10 +13,10 @@ if(!defined('HOME_LINK_OTHERS')){ } //Version -define('VERSION', '20.2.0.OS'); -define('CACHE_VALUE', '20.2.0.OS'); -define('VERSION_NUMBER', '2020'); -define('VERSION_DATE', '28/09/2017'); +define('VERSION', '20.3.0.OS'); +define('CACHE_VALUE', '20.3.0.OS'); +define('VERSION_NUMBER', '2030'); +define('VERSION_DATE', '26/11/2017'); if(!defined('CONTACT_EMAIL')){define('CONTACT_EMAIL','icehrm@gamonoid.com');} if(!defined('KEY_PREFIX')){define('KEY_PREFIX','IceHrm');} diff --git a/release.md b/release.md index 1ec4d833..70df2eb7 100644 --- a/release.md +++ b/release.md @@ -1,3 +1,16 @@ +Release note v20.3.0.OS +----------------------- +### Features + * Employee and Attendance REST Api Released + * Import/Export for Payroll Configurations + * Ability to import employee approved time sheet hours to payroll + * Swift Mailer based SMTP support (no need to install Net_SMTP anymore) + * Add direct Edit button on employee list + +### Fixes + * Fix DB connection issues due to special characters in password + * Fixes for custom field saving issues in mysql v5.7.x + Release note v20.2 ------------------ ### Fixes