├── Locale ├── cs_CZ │ └── translations.php ├── da_DK │ └── translations.php ├── de_DE │ └── translations.php ├── es_ES │ └── translations.php ├── fi_FI │ └── translations.php ├── fr_FR │ └── translations.php ├── hu_HU │ └── translations.php ├── id_ID │ └── translations.php ├── it_IT │ └── translations.php ├── ja_JP │ └── translations.php ├── nb_NO │ └── translations.php ├── nl_NL │ └── translations.php ├── pl_PL │ └── translations.php ├── pt_BR │ └── translations.php ├── pt_PT │ └── translations.php ├── ru_RU │ └── translations.php ├── sr_Latn_RS │ └── translations.php ├── sv_SE │ └── translations.php ├── th_TH │ └── translations.php ├── tr_TR │ └── translations.php └── zh_CN │ └── translations.php ├── Plugin.php ├── README.md ├── Template └── integration.php ├── composer.json ├── composer.lock ├── cron.php ├── imap-icon.png └── vendor ├── autoload.php ├── composer ├── ClassLoader.php ├── LICENSE ├── autoload_classmap.php ├── autoload_namespaces.php ├── autoload_psr4.php ├── autoload_real.php ├── autoload_static.php └── installed.json ├── fguillot └── json-rpc │ ├── LICENSE │ └── src │ └── JsonRPC │ ├── Client.php │ ├── Exception │ ├── AccessDeniedException.php │ ├── AuthenticationFailureException.php │ ├── ConnectionFailureException.php │ ├── InvalidJsonFormatException.php │ ├── InvalidJsonRpcFormatException.php │ ├── ResponseEncodingFailureException.php │ ├── ResponseException.php │ └── ServerErrorException.php │ ├── HttpClient.php │ ├── MiddlewareHandler.php │ ├── MiddlewareInterface.php │ ├── ProcedureHandler.php │ ├── Request │ ├── BatchRequestParser.php │ ├── RequestBuilder.php │ └── RequestParser.php │ ├── Response │ ├── ResponseBuilder.php │ └── ResponseParser.php │ ├── Server.php │ └── Validator │ ├── HostValidator.php │ ├── JsonEncodingValidator.php │ ├── JsonFormatValidator.php │ ├── RpcFormatValidator.php │ └── UserValidator.php └── tedivm └── fetch ├── .coveralls.yml ├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── autoload.php ├── composer.json ├── phpunit.xml.dist ├── src └── Fetch │ ├── Attachment.php │ ├── Message.php │ └── Server.php └── tests ├── Fetch └── Test │ ├── AttachmentTest.php │ ├── MessageTest.php │ └── ServerTest.php ├── bootstrap.php └── runTests.sh /Locale/cs_CZ/translations.php: -------------------------------------------------------------------------------- 1 | 'Hilfe bei Mailgun-Integration', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/da_DK/translations.php: -------------------------------------------------------------------------------- 1 | '', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/de_DE/translations.php: -------------------------------------------------------------------------------- 1 | 'Hilfe bei Mailgun-Integration', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/es_ES/translations.php: -------------------------------------------------------------------------------- 1 | 'Ayuda sobre la integración con Mailgun', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/fi_FI/translations.php: -------------------------------------------------------------------------------- 1 | '', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/fr_FR/translations.php: -------------------------------------------------------------------------------- 1 | 'Aide sur l\'intégration avec Mailgun', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/hu_HU/translations.php: -------------------------------------------------------------------------------- 1 | '', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/id_ID/translations.php: -------------------------------------------------------------------------------- 1 | 'Bantuan pada integrasi Mailgun', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/it_IT/translations.php: -------------------------------------------------------------------------------- 1 | '', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/ja_JP/translations.php: -------------------------------------------------------------------------------- 1 | '', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/nb_NO/translations.php: -------------------------------------------------------------------------------- 1 | '', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/nl_NL/translations.php: -------------------------------------------------------------------------------- 1 | '', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/pl_PL/translations.php: -------------------------------------------------------------------------------- 1 | '', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/pt_BR/translations.php: -------------------------------------------------------------------------------- 1 | 'Ajuda na integração do Mailgun', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/pt_PT/translations.php: -------------------------------------------------------------------------------- 1 | 'Ajuda na integração do Mailgun', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/ru_RU/translations.php: -------------------------------------------------------------------------------- 1 | 'Справка о Mailgun интеграции', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/sr_Latn_RS/translations.php: -------------------------------------------------------------------------------- 1 | '', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/sv_SE/translations.php: -------------------------------------------------------------------------------- 1 | 'Hjälp för Mailgrun integration', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/th_TH/translations.php: -------------------------------------------------------------------------------- 1 | '', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/tr_TR/translations.php: -------------------------------------------------------------------------------- 1 | '', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Locale/zh_CN/translations.php: -------------------------------------------------------------------------------- 1 | '', 5 | ); 6 | 7 | -------------------------------------------------------------------------------- /Plugin.php: -------------------------------------------------------------------------------- 1 | template->hook->attach('template:config:integrations', 'imap:integration'); 20 | } 21 | 22 | public function onStartup() 23 | { 24 | Translator::load($this->languageModel->getCurrentLanguage(), __DIR__.'/Locale'); 25 | } 26 | 27 | public function getPluginDescription() 28 | { 29 | return 'Imap Email Integration'; 30 | } 31 | 32 | public function getPluginAuthor() 33 | { 34 | return 'Esteban Monge'; 35 | } 36 | 37 | public function getPluginVersion() 38 | { 39 | return '0.0.1'; 40 | } 41 | 42 | public function getPluginHomepage() 43 | { 44 | return 'https://github.com/EstebanMonge'; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Kanboard IMAP Tasks 2 | ===================== 3 | 4 | 5 | - Create tasks by mails fetched from IMAP 6 | 7 | Author 8 | ------ 9 | 10 | - Esteban Monge 11 | - License MIT 12 | 13 | Based in the work of Frédéric Guillot from Mailgun plugin hosted on https://github.com/kanboard/plugin-mailgun 14 | and the work of polom from kanboard-tasksbymail scripts hosted on https://github.com/polom/kanboard-tasksbymail 15 | 16 | Requirements 17 | ------------ 18 | 19 | - Kanboard >= 1.0.33 20 | - PHP 5.6 or >= 7.0.0 21 | 22 | Installation 23 | ------------ 24 | 25 | You have the choice between 2 methods: 26 | 27 | 1. Download the zip file and decompress everything under the directory `plugins/Imap` 28 | 2. Clone this repository into the folder `plugins/Imap` 29 | 30 | Finally add a crontab with this line: 31 | 32 | * * * * * /path/to/kanboard/plugins/Imap/cron.php /path/to/kanboad/data/db.sqlite 33 | 34 | Note: Plugin folder is case-sensitive. 35 | 36 | Configuration 37 | ------------- 38 | 39 | Go to Kanboard -> Settings -> Integrations 40 | Go to Kanboard -> Project -> Menu -> Settings -> Edit project and add a Identifier 41 | 42 | Testing 43 | ------- 44 | 45 | You can send a email with this format happykanboard+PROJECTIDENTIFIER@riseup.net put a subject that will be the task title and details in the email body that will be the task content. 46 | 47 | You can also send a email with this format in subject: Finish Duke Nukem Forever 2 \ please! Finish Duke Nukem Forever 2 please! will be the title and details in the email body that will be the task content. 48 | -------------------------------------------------------------------------------- /Template/integration.php: -------------------------------------------------------------------------------- 1 |

 Imap

2 |
3 | 4 | form->label(t('IMAP Server'), 'imap_server') ?> 5 | form->text('imap_server', $values) ?> 6 | 7 | form->label(t('IMAP Server Port'), 'imap_server_port') ?> 8 | form->text('imap_server_port', $values) ?> 9 | 10 | form->label(t('IMAP Server Requires SSL'), 'imap_server_requires_ssl') ?> 11 | form->text('imap_server_requires_ssl', $values) ?> 12 | 13 | form->label(t('IMAP Username'), 'imap_username') ?> 14 | form->text('imap_username', $values) ?> 15 | 16 | form->label(t('IMAP Password'), 'imap_password') ?> 17 | form->password('imap_password', $values) ?> 18 | 19 | form->label(t('Mail prefix'), 'imap_mail_prefix') ?> 20 | form->text('imap_mail_prefix', $values) ?> 21 | 22 | form->label(t('Application URL or Localhost Application URL'), 'imap_application_url') ?> 23 | form->text('imap_application_url', $values) ?> 24 | 25 | form->label(t('Guest User ID'), 'imap_guest_user_id') ?> 26 | form->text('imap_guest_user_id', $values) ?> 27 | 28 | form->label(t('Default priority'), 'imap_default_priority') ?> 29 | form->text('imap_default_priority', $values) ?> 30 | 31 | form->label(t('Mail body message'), 'imap_body_message') ?> 32 | form->text('imap_body_message', $values) ?> 33 | 34 | form->label(t('Task description message'), 'imap_task_description_message') ?> 35 | form->text('imap_task_description_message', $values) ?> 36 | 37 |
38 | 39 |
40 |
41 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "fguillot/json-rpc": "1.2.3", 4 | "tedivm/fetch": "0.7.*" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "e689a9db3d8223122f2e559f3c42261e", 8 | "content-hash": "fde413430434506f423aeec4bab91e82", 9 | "packages": [ 10 | { 11 | "name": "fguillot/json-rpc", 12 | "version": "v1.2.3", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/fguillot/JsonRPC.git", 16 | "reference": "86dd3cf0724bc495cb31882122e9a3a77b9a2ffc" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/86dd3cf0724bc495cb31882122e9a3a77b9a2ffc", 21 | "reference": "86dd3cf0724bc495cb31882122e9a3a77b9a2ffc", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "php": ">=5.3.4" 26 | }, 27 | "require-dev": { 28 | "phpunit/phpunit": "4.8.*" 29 | }, 30 | "type": "library", 31 | "autoload": { 32 | "psr-0": { 33 | "JsonRPC": "src/" 34 | } 35 | }, 36 | "notification-url": "https://packagist.org/downloads/", 37 | "license": [ 38 | "MIT" 39 | ], 40 | "authors": [ 41 | { 42 | "name": "Frédéric Guillot" 43 | } 44 | ], 45 | "description": "Simple Json-RPC client/server library that just works", 46 | "homepage": "https://github.com/fguillot/JsonRPC", 47 | "time": "2016-12-15 03:00:30" 48 | }, 49 | { 50 | "name": "tedivm/fetch", 51 | "version": "v0.7.1", 52 | "source": { 53 | "type": "git", 54 | "url": "https://github.com/tedious/Fetch.git", 55 | "reference": "ea3f1bbde6bd6388488105240640642dc82c06a6" 56 | }, 57 | "dist": { 58 | "type": "zip", 59 | "url": "https://api.github.com/repos/tedious/Fetch/zipball/ea3f1bbde6bd6388488105240640642dc82c06a6", 60 | "reference": "ea3f1bbde6bd6388488105240640642dc82c06a6", 61 | "shasum": "" 62 | }, 63 | "require": { 64 | "ext-imap": "*", 65 | "php": ">=5.3.0" 66 | }, 67 | "require-dev": { 68 | "fabpot/php-cs-fixer": "0.5.*", 69 | "phpunit/phpunit": "4.2.*", 70 | "satooshi/php-coveralls": "dev-master", 71 | "tedivm/dovecottesting": "1.2.3" 72 | }, 73 | "type": "library", 74 | "autoload": { 75 | "psr-0": { 76 | "Fetch": "src/" 77 | } 78 | }, 79 | "notification-url": "https://packagist.org/downloads/", 80 | "license": [ 81 | "BSD-3-Clause" 82 | ], 83 | "authors": [ 84 | { 85 | "name": "Robert Hafner", 86 | "email": "tedivm@tedivm.com" 87 | } 88 | ], 89 | "description": "A PHP IMAP Library", 90 | "homepage": "http://github.com/tedious/Fetch", 91 | "keywords": [ 92 | "email", 93 | "imap", 94 | "pop3" 95 | ], 96 | "time": "2015-08-02 03:38:12" 97 | } 98 | ], 99 | "packages-dev": [], 100 | "aliases": [], 101 | "minimum-stability": "stable", 102 | "stability-flags": [], 103 | "prefer-stable": false, 104 | "prefer-lowest": false, 105 | "platform": [], 106 | "platform-dev": [] 107 | } 108 | -------------------------------------------------------------------------------- /cron.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | query('SELECT option,value from settings where option IN ("imap_body_message","imap_default_priority","imap_server","imap_username","imap_password","imap_server_port","imap_server_requires_ssl","imap_mail_prefix","api_token","imap_application_url","imap_guest_user_id","imap_task_description_message")'); 21 | while ($row = $results->fetchArray()) { 22 | switch ($row['option']) { 23 | case "imap_server": 24 | $imap_server = $row['value']; 25 | break; 26 | case "imap_username": 27 | $imap_username = $row['value']; 28 | break; 29 | case "imap_password": 30 | $imap_password = $row['value']; 31 | break; 32 | case "imap_server_port": 33 | $imap_server_port = $row['value']; 34 | break; 35 | case "imap_server_requires_ssl": 36 | $imap_server_requires_ssl = $row['value']; 37 | break; 38 | case "imap_mail_prefix": 39 | $mail_prefix = $row['value']; 40 | break; 41 | case "api_token": 42 | $jsonrpc_auth_token = $row['value']; 43 | break; 44 | case "imap_application_url": 45 | $jsonrpc_url= $row['value']; 46 | break; 47 | case "imap_guest_user_id": 48 | $imap_guest_user_id= $row['value']; 49 | break; 50 | case "imap_default_priority": 51 | $default_priority= $row['value']; 52 | break; 53 | case "imap_body_message": 54 | $body_message= $row['value']; 55 | break; 56 | case "imap_task_description_message": 57 | $task_description_message= $row['value']; 58 | break; 59 | 60 | } 61 | } 62 | $client = new JsonRPC\Client($jsonrpc_url); 63 | $client->authentication($jsonrpc_auth_name, $jsonrpc_auth_token); 64 | $projects_tmp = $client->execute('getAllProjects'); 65 | $users_tmp= $client->execute('getAllUsers'); 66 | foreach ($projects_tmp as $proj) { 67 | if ($proj['identifier']){ 68 | $projects[$proj['identifier']]['id'] = $proj['id']; 69 | } 70 | } 71 | $server = new Server($imap_server,993); 72 | $server->setAuthentication($imap_username, $imap_password); 73 | $messages = $server->search('UNSEEN'); 74 | foreach ($messages as $message) { 75 | $body_text=$message->getMessageBody(); 76 | $body_html=$message->getMessageBody($html=true); 77 | preg_match('~TaskID#\[(.*?)\]~', $message->getSubject(), $output); 78 | $task_id = $output[1]; 79 | $to = $message->getAddresses("to"); 80 | $cc = $message->getAddresses("cc"); 81 | $from = $message->getAddresses("from"); 82 | $header=$message->getHeaders(); 83 | foreach ($cc as $ccfor) { 84 | if ( "$imap_username" != $ccfor['address'] ) { 85 | $ccaddress .= $ccfor['address'].","; 86 | } 87 | } 88 | $ccaddress=substr_replace($ccaddress, "", -1); 89 | foreach ($to as $tofor) { 90 | if ( "$imap_username" != $tofor['address'] ) { 91 | $toaddress .= $tofor['address'].","; 92 | } 93 | } 94 | $toaddress=substr_replace($toaddress, "", -1); 95 | $comment['user_id'] = $imap_guest_user_id; 96 | $task['creator_id'] = $imap_guest_user_id; 97 | foreach ($users_tmp as $user) { 98 | if ( strtolower($user['email']) == strtolower($from['address']) ){ 99 | $comment['user_id'] = $user['id']; 100 | $task['creator_id'] = $user['id']; 101 | } 102 | } 103 | if ( $comment['user_id']==$imap_guest_user_id && $imap_guest_user_id != "" ) { 104 | $comment['content'].="From: ".strtolower($from['address'])."\r\n"; 105 | $task['description'].="From: ".strtolower($from['address'])."\r\n"; 106 | } 107 | 108 | if ( $client->getTask($task_id) ) { 109 | $comment['task_id']=$task_id; 110 | $comment['content'].=$body_text; 111 | $response=$client->createComment($comment); 112 | } 113 | else { 114 | if (strpos($to[0]['address'],$mail_prefix) !== false){ 115 | $project_identifier = str_replace($mail_prefix,'',$to[0]['address']); 116 | $project_identifier = strstr($project_identifier, '@', true); 117 | if (isset($projects[strtoupper($project_identifier)])) { 118 | $task['project_id'] = $projects[strtoupper($project_identifier)]['id']; 119 | } 120 | } 121 | else { 122 | preg_match('~<(.*?)>~', $message->getSubject(), $output); 123 | $project_identifier = $output[1]; 124 | if (isset($projects[strtoupper($project_identifier)])) { 125 | $task['project_id'] = $projects[strtoupper($project_identifier)]['id']; 126 | } 127 | } 128 | $task['title'] = str_replace("<$project_identifier>",'',$message->getSubject()); 129 | $task['description'] .= "\r\n".$task_description_message."\r\n"; 130 | $task['description'] .= $body_text; 131 | $task['priority'] = $default_priority; 132 | $task_id = $client->createTask($task); 133 | 134 | $subject = "Re: ".$message->getSubject()." TaskID#[".$task_id."]"; 135 | $body_message=str_replace('$task_id',$task_id,$body_message); 136 | $body_message.="

----- Mensaje Original -----

"; 137 | $body_message.="From: ".$from['address']."\n"; 138 | $body_message.="To: ".$toaddress."\n"; 139 | $body_message.="Cc: ".$ccaddress."\n"; 140 | $body_message.="$body_html"; 141 | $headers = 'MIME-Version: 1.0' . "\r\n"; 142 | $headers .= 'Content-type: text/html; charset=UTF-8' . "\r\n"; 143 | $headers .= 'From: '.$imap_username. "\r\n" . 144 | 'Reply-To: <'.$imap_username.'>'. "\r\n" . 145 | 'Subject: '.$subject."\r\n". 146 | 'To: '.$from['address']."\r\n". 147 | 'CC: '.$toaddress.','.$ccaddress."\r\n". 148 | 'In-Reply-To: <'.$header->message_id.'>'. "\r\n" . 149 | 'References: <'.$header->message_id.'>'. "\r\n" . 150 | 'X-Mailer: PHP/' . phpversion(); 151 | mail($toaddress,$subject,$body_message,$headers); } 152 | } 153 | } 154 | else 155 | { 156 | echo "You must specify the database path\n"; 157 | } 158 | ?> 159 | -------------------------------------------------------------------------------- /imap-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EstebanMonge/kanboard_imap_tasks/316a1d9fede76fc70557fd9f57bee0639b2e91ca/imap-icon.png -------------------------------------------------------------------------------- /vendor/autoload.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Autoload; 14 | 15 | /** 16 | * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. 17 | * 18 | * $loader = new \Composer\Autoload\ClassLoader(); 19 | * 20 | * // register classes with namespaces 21 | * $loader->add('Symfony\Component', __DIR__.'/component'); 22 | * $loader->add('Symfony', __DIR__.'/framework'); 23 | * 24 | * // activate the autoloader 25 | * $loader->register(); 26 | * 27 | * // to enable searching the include path (eg. for PEAR packages) 28 | * $loader->setUseIncludePath(true); 29 | * 30 | * In this example, if you try to use a class in the Symfony\Component 31 | * namespace or one of its children (Symfony\Component\Console for instance), 32 | * the autoloader will first look for the class under the component/ 33 | * directory, and it will then fallback to the framework/ directory if not 34 | * found before giving up. 35 | * 36 | * This class is loosely based on the Symfony UniversalClassLoader. 37 | * 38 | * @author Fabien Potencier 39 | * @author Jordi Boggiano 40 | * @see http://www.php-fig.org/psr/psr-0/ 41 | * @see http://www.php-fig.org/psr/psr-4/ 42 | */ 43 | class ClassLoader 44 | { 45 | // PSR-4 46 | private $prefixLengthsPsr4 = array(); 47 | private $prefixDirsPsr4 = array(); 48 | private $fallbackDirsPsr4 = array(); 49 | 50 | // PSR-0 51 | private $prefixesPsr0 = array(); 52 | private $fallbackDirsPsr0 = array(); 53 | 54 | private $useIncludePath = false; 55 | private $classMap = array(); 56 | private $classMapAuthoritative = false; 57 | private $missingClasses = array(); 58 | 59 | public function getPrefixes() 60 | { 61 | if (!empty($this->prefixesPsr0)) { 62 | return call_user_func_array('array_merge', $this->prefixesPsr0); 63 | } 64 | 65 | return array(); 66 | } 67 | 68 | public function getPrefixesPsr4() 69 | { 70 | return $this->prefixDirsPsr4; 71 | } 72 | 73 | public function getFallbackDirs() 74 | { 75 | return $this->fallbackDirsPsr0; 76 | } 77 | 78 | public function getFallbackDirsPsr4() 79 | { 80 | return $this->fallbackDirsPsr4; 81 | } 82 | 83 | public function getClassMap() 84 | { 85 | return $this->classMap; 86 | } 87 | 88 | /** 89 | * @param array $classMap Class to filename map 90 | */ 91 | public function addClassMap(array $classMap) 92 | { 93 | if ($this->classMap) { 94 | $this->classMap = array_merge($this->classMap, $classMap); 95 | } else { 96 | $this->classMap = $classMap; 97 | } 98 | } 99 | 100 | /** 101 | * Registers a set of PSR-0 directories for a given prefix, either 102 | * appending or prepending to the ones previously set for this prefix. 103 | * 104 | * @param string $prefix The prefix 105 | * @param array|string $paths The PSR-0 root directories 106 | * @param bool $prepend Whether to prepend the directories 107 | */ 108 | public function add($prefix, $paths, $prepend = false) 109 | { 110 | if (!$prefix) { 111 | if ($prepend) { 112 | $this->fallbackDirsPsr0 = array_merge( 113 | (array) $paths, 114 | $this->fallbackDirsPsr0 115 | ); 116 | } else { 117 | $this->fallbackDirsPsr0 = array_merge( 118 | $this->fallbackDirsPsr0, 119 | (array) $paths 120 | ); 121 | } 122 | 123 | return; 124 | } 125 | 126 | $first = $prefix[0]; 127 | if (!isset($this->prefixesPsr0[$first][$prefix])) { 128 | $this->prefixesPsr0[$first][$prefix] = (array) $paths; 129 | 130 | return; 131 | } 132 | if ($prepend) { 133 | $this->prefixesPsr0[$first][$prefix] = array_merge( 134 | (array) $paths, 135 | $this->prefixesPsr0[$first][$prefix] 136 | ); 137 | } else { 138 | $this->prefixesPsr0[$first][$prefix] = array_merge( 139 | $this->prefixesPsr0[$first][$prefix], 140 | (array) $paths 141 | ); 142 | } 143 | } 144 | 145 | /** 146 | * Registers a set of PSR-4 directories for a given namespace, either 147 | * appending or prepending to the ones previously set for this namespace. 148 | * 149 | * @param string $prefix The prefix/namespace, with trailing '\\' 150 | * @param array|string $paths The PSR-4 base directories 151 | * @param bool $prepend Whether to prepend the directories 152 | * 153 | * @throws \InvalidArgumentException 154 | */ 155 | public function addPsr4($prefix, $paths, $prepend = false) 156 | { 157 | if (!$prefix) { 158 | // Register directories for the root namespace. 159 | if ($prepend) { 160 | $this->fallbackDirsPsr4 = array_merge( 161 | (array) $paths, 162 | $this->fallbackDirsPsr4 163 | ); 164 | } else { 165 | $this->fallbackDirsPsr4 = array_merge( 166 | $this->fallbackDirsPsr4, 167 | (array) $paths 168 | ); 169 | } 170 | } elseif (!isset($this->prefixDirsPsr4[$prefix])) { 171 | // Register directories for a new namespace. 172 | $length = strlen($prefix); 173 | if ('\\' !== $prefix[$length - 1]) { 174 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 175 | } 176 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 177 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 178 | } elseif ($prepend) { 179 | // Prepend directories for an already registered namespace. 180 | $this->prefixDirsPsr4[$prefix] = array_merge( 181 | (array) $paths, 182 | $this->prefixDirsPsr4[$prefix] 183 | ); 184 | } else { 185 | // Append directories for an already registered namespace. 186 | $this->prefixDirsPsr4[$prefix] = array_merge( 187 | $this->prefixDirsPsr4[$prefix], 188 | (array) $paths 189 | ); 190 | } 191 | } 192 | 193 | /** 194 | * Registers a set of PSR-0 directories for a given prefix, 195 | * replacing any others previously set for this prefix. 196 | * 197 | * @param string $prefix The prefix 198 | * @param array|string $paths The PSR-0 base directories 199 | */ 200 | public function set($prefix, $paths) 201 | { 202 | if (!$prefix) { 203 | $this->fallbackDirsPsr0 = (array) $paths; 204 | } else { 205 | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; 206 | } 207 | } 208 | 209 | /** 210 | * Registers a set of PSR-4 directories for a given namespace, 211 | * replacing any others previously set for this namespace. 212 | * 213 | * @param string $prefix The prefix/namespace, with trailing '\\' 214 | * @param array|string $paths The PSR-4 base directories 215 | * 216 | * @throws \InvalidArgumentException 217 | */ 218 | public function setPsr4($prefix, $paths) 219 | { 220 | if (!$prefix) { 221 | $this->fallbackDirsPsr4 = (array) $paths; 222 | } else { 223 | $length = strlen($prefix); 224 | if ('\\' !== $prefix[$length - 1]) { 225 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 226 | } 227 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 228 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 229 | } 230 | } 231 | 232 | /** 233 | * Turns on searching the include path for class files. 234 | * 235 | * @param bool $useIncludePath 236 | */ 237 | public function setUseIncludePath($useIncludePath) 238 | { 239 | $this->useIncludePath = $useIncludePath; 240 | } 241 | 242 | /** 243 | * Can be used to check if the autoloader uses the include path to check 244 | * for classes. 245 | * 246 | * @return bool 247 | */ 248 | public function getUseIncludePath() 249 | { 250 | return $this->useIncludePath; 251 | } 252 | 253 | /** 254 | * Turns off searching the prefix and fallback directories for classes 255 | * that have not been registered with the class map. 256 | * 257 | * @param bool $classMapAuthoritative 258 | */ 259 | public function setClassMapAuthoritative($classMapAuthoritative) 260 | { 261 | $this->classMapAuthoritative = $classMapAuthoritative; 262 | } 263 | 264 | /** 265 | * Should class lookup fail if not found in the current class map? 266 | * 267 | * @return bool 268 | */ 269 | public function isClassMapAuthoritative() 270 | { 271 | return $this->classMapAuthoritative; 272 | } 273 | 274 | /** 275 | * Registers this instance as an autoloader. 276 | * 277 | * @param bool $prepend Whether to prepend the autoloader or not 278 | */ 279 | public function register($prepend = false) 280 | { 281 | spl_autoload_register(array($this, 'loadClass'), true, $prepend); 282 | } 283 | 284 | /** 285 | * Unregisters this instance as an autoloader. 286 | */ 287 | public function unregister() 288 | { 289 | spl_autoload_unregister(array($this, 'loadClass')); 290 | } 291 | 292 | /** 293 | * Loads the given class or interface. 294 | * 295 | * @param string $class The name of the class 296 | * @return bool|null True if loaded, null otherwise 297 | */ 298 | public function loadClass($class) 299 | { 300 | if ($file = $this->findFile($class)) { 301 | includeFile($file); 302 | 303 | return true; 304 | } 305 | } 306 | 307 | /** 308 | * Finds the path to the file where the class is defined. 309 | * 310 | * @param string $class The name of the class 311 | * 312 | * @return string|false The path if found, false otherwise 313 | */ 314 | public function findFile($class) 315 | { 316 | // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 317 | if ('\\' == $class[0]) { 318 | $class = substr($class, 1); 319 | } 320 | 321 | // class map lookup 322 | if (isset($this->classMap[$class])) { 323 | return $this->classMap[$class]; 324 | } 325 | if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { 326 | return false; 327 | } 328 | 329 | $file = $this->findFileWithExtension($class, '.php'); 330 | 331 | // Search for Hack files if we are running on HHVM 332 | if (false === $file && defined('HHVM_VERSION')) { 333 | $file = $this->findFileWithExtension($class, '.hh'); 334 | } 335 | 336 | if (false === $file) { 337 | // Remember that this class does not exist. 338 | $this->missingClasses[$class] = true; 339 | } 340 | 341 | return $file; 342 | } 343 | 344 | private function findFileWithExtension($class, $ext) 345 | { 346 | // PSR-4 lookup 347 | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; 348 | 349 | $first = $class[0]; 350 | if (isset($this->prefixLengthsPsr4[$first])) { 351 | foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { 352 | if (0 === strpos($class, $prefix)) { 353 | foreach ($this->prefixDirsPsr4[$prefix] as $dir) { 354 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { 355 | return $file; 356 | } 357 | } 358 | } 359 | } 360 | } 361 | 362 | // PSR-4 fallback dirs 363 | foreach ($this->fallbackDirsPsr4 as $dir) { 364 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { 365 | return $file; 366 | } 367 | } 368 | 369 | // PSR-0 lookup 370 | if (false !== $pos = strrpos($class, '\\')) { 371 | // namespaced class name 372 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) 373 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); 374 | } else { 375 | // PEAR-like class name 376 | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; 377 | } 378 | 379 | if (isset($this->prefixesPsr0[$first])) { 380 | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { 381 | if (0 === strpos($class, $prefix)) { 382 | foreach ($dirs as $dir) { 383 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 384 | return $file; 385 | } 386 | } 387 | } 388 | } 389 | } 390 | 391 | // PSR-0 fallback dirs 392 | foreach ($this->fallbackDirsPsr0 as $dir) { 393 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 394 | return $file; 395 | } 396 | } 397 | 398 | // PSR-0 include paths. 399 | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { 400 | return $file; 401 | } 402 | 403 | return false; 404 | } 405 | } 406 | 407 | /** 408 | * Scope isolated include. 409 | * 410 | * Prevents access to $this/self from included files. 411 | */ 412 | function includeFile($file) 413 | { 414 | include $file; 415 | } 416 | -------------------------------------------------------------------------------- /vendor/composer/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2016 Nils Adermann, Jordi Boggiano 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is furnished 9 | to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /vendor/composer/autoload_classmap.php: -------------------------------------------------------------------------------- 1 | array($vendorDir . '/fguillot/json-rpc/src'), 10 | 'Fetch' => array($vendorDir . '/tedivm/fetch/src'), 11 | ); 12 | -------------------------------------------------------------------------------- /vendor/composer/autoload_psr4.php: -------------------------------------------------------------------------------- 1 | = 50600 && !defined('HHVM_VERSION'); 27 | if ($useStaticLoader) { 28 | require_once __DIR__ . '/autoload_static.php'; 29 | 30 | call_user_func(\Composer\Autoload\ComposerStaticInit3ae4b3fce9460942cfa4cb3349a9f36d::getInitializer($loader)); 31 | } else { 32 | $map = require __DIR__ . '/autoload_namespaces.php'; 33 | foreach ($map as $namespace => $path) { 34 | $loader->set($namespace, $path); 35 | } 36 | 37 | $map = require __DIR__ . '/autoload_psr4.php'; 38 | foreach ($map as $namespace => $path) { 39 | $loader->setPsr4($namespace, $path); 40 | } 41 | 42 | $classMap = require __DIR__ . '/autoload_classmap.php'; 43 | if ($classMap) { 44 | $loader->addClassMap($classMap); 45 | } 46 | } 47 | 48 | $loader->register(true); 49 | 50 | return $loader; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /vendor/composer/autoload_static.php: -------------------------------------------------------------------------------- 1 | 11 | array ( 12 | 'JsonRPC' => 13 | array ( 14 | 0 => __DIR__ . '/..' . '/fguillot/json-rpc/src', 15 | ), 16 | ), 17 | 'F' => 18 | array ( 19 | 'Fetch' => 20 | array ( 21 | 0 => __DIR__ . '/..' . '/tedivm/fetch/src', 22 | ), 23 | ), 24 | ); 25 | 26 | public static function getInitializer(ClassLoader $loader) 27 | { 28 | return \Closure::bind(function () use ($loader) { 29 | $loader->prefixesPsr0 = ComposerStaticInit3ae4b3fce9460942cfa4cb3349a9f36d::$prefixesPsr0; 30 | 31 | }, null, ClassLoader::class); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /vendor/composer/installed.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "fguillot/json-rpc", 4 | "version": "v1.2.3", 5 | "version_normalized": "1.2.3.0", 6 | "source": { 7 | "type": "git", 8 | "url": "https://github.com/fguillot/JsonRPC.git", 9 | "reference": "86dd3cf0724bc495cb31882122e9a3a77b9a2ffc" 10 | }, 11 | "dist": { 12 | "type": "zip", 13 | "url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/86dd3cf0724bc495cb31882122e9a3a77b9a2ffc", 14 | "reference": "86dd3cf0724bc495cb31882122e9a3a77b9a2ffc", 15 | "shasum": "" 16 | }, 17 | "require": { 18 | "php": ">=5.3.4" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": "4.8.*" 22 | }, 23 | "time": "2016-12-15 03:00:30", 24 | "type": "library", 25 | "installation-source": "dist", 26 | "autoload": { 27 | "psr-0": { 28 | "JsonRPC": "src/" 29 | } 30 | }, 31 | "notification-url": "https://packagist.org/downloads/", 32 | "license": [ 33 | "MIT" 34 | ], 35 | "authors": [ 36 | { 37 | "name": "Frédéric Guillot" 38 | } 39 | ], 40 | "description": "Simple Json-RPC client/server library that just works", 41 | "homepage": "https://github.com/fguillot/JsonRPC" 42 | }, 43 | { 44 | "name": "tedivm/fetch", 45 | "version": "v0.7.1", 46 | "version_normalized": "0.7.1.0", 47 | "source": { 48 | "type": "git", 49 | "url": "https://github.com/tedious/Fetch.git", 50 | "reference": "ea3f1bbde6bd6388488105240640642dc82c06a6" 51 | }, 52 | "dist": { 53 | "type": "zip", 54 | "url": "https://api.github.com/repos/tedious/Fetch/zipball/ea3f1bbde6bd6388488105240640642dc82c06a6", 55 | "reference": "ea3f1bbde6bd6388488105240640642dc82c06a6", 56 | "shasum": "" 57 | }, 58 | "require": { 59 | "ext-imap": "*", 60 | "php": ">=5.3.0" 61 | }, 62 | "require-dev": { 63 | "fabpot/php-cs-fixer": "0.5.*", 64 | "phpunit/phpunit": "4.2.*", 65 | "satooshi/php-coveralls": "dev-master", 66 | "tedivm/dovecottesting": "1.2.3" 67 | }, 68 | "time": "2015-08-02 03:38:12", 69 | "type": "library", 70 | "installation-source": "dist", 71 | "autoload": { 72 | "psr-0": { 73 | "Fetch": "src/" 74 | } 75 | }, 76 | "notification-url": "https://packagist.org/downloads/", 77 | "license": [ 78 | "BSD-3-Clause" 79 | ], 80 | "authors": [ 81 | { 82 | "name": "Robert Hafner", 83 | "email": "tedivm@tedivm.com" 84 | } 85 | ], 86 | "description": "A PHP IMAP Library", 87 | "homepage": "http://github.com/tedious/Fetch", 88 | "keywords": [ 89 | "email", 90 | "imap", 91 | "pop3" 92 | ] 93 | } 94 | ] 95 | -------------------------------------------------------------------------------- /vendor/fguillot/json-rpc/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Frederic Guillot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/fguillot/json-rpc/src/JsonRPC/Client.php: -------------------------------------------------------------------------------- 1 | httpClient = $httpClient ?: new HttpClient($url); 69 | $this->returnException = $returnException; 70 | } 71 | 72 | /** 73 | * Arguments passed are always positional 74 | * 75 | * @access public 76 | * @return $this 77 | */ 78 | public function withPositionalArguments() 79 | { 80 | $this->isNamedArguments = false; 81 | return $this; 82 | } 83 | 84 | /** 85 | * Get HTTP Client 86 | * 87 | * @access public 88 | * @return HttpClient 89 | */ 90 | public function getHttpClient() 91 | { 92 | return $this->httpClient; 93 | } 94 | 95 | /** 96 | * Set username and password 97 | * 98 | * @access public 99 | * @param string $username 100 | * @param string $password 101 | * @return $this 102 | */ 103 | public function authentication($username, $password) 104 | { 105 | $this->httpClient 106 | ->withUsername($username) 107 | ->withPassword($password); 108 | 109 | return $this; 110 | } 111 | 112 | /** 113 | * Automatic mapping of procedures 114 | * 115 | * @access public 116 | * @param string $method Procedure name 117 | * @param array $params Procedure arguments 118 | * @return mixed 119 | */ 120 | public function __call($method, array $params) 121 | { 122 | if ($this->isNamedArguments && count($params) === 1 && is_array($params[0])) { 123 | $params = $params[0]; 124 | } 125 | 126 | return $this->execute($method, $params); 127 | } 128 | 129 | /** 130 | * Start a batch request 131 | * 132 | * @access public 133 | * @return Client 134 | */ 135 | public function batch() 136 | { 137 | $this->isBatch = true; 138 | $this->batch = array(); 139 | return $this; 140 | } 141 | 142 | /** 143 | * Send a batch request 144 | * 145 | * @access public 146 | * @return array 147 | */ 148 | public function send() 149 | { 150 | $this->isBatch = false; 151 | return $this->sendPayload('['.implode(', ', $this->batch).']'); 152 | } 153 | 154 | /** 155 | * Execute a procedure 156 | * 157 | * @access public 158 | * @param string $procedure Procedure name 159 | * @param array $params Procedure arguments 160 | * @param array $reqattrs 161 | * @param string|null $requestId Request Id 162 | * @return mixed 163 | */ 164 | public function execute($procedure, array $params = array(), array $reqattrs = array(), $requestId = null) 165 | { 166 | $payload = RequestBuilder::create() 167 | ->withProcedure($procedure) 168 | ->withParams($params) 169 | ->withRequestAttributes($reqattrs) 170 | ->withId($requestId) 171 | ->build(); 172 | 173 | if ($this->isBatch) { 174 | $this->batch[] = $payload; 175 | return $this; 176 | } 177 | 178 | return $this->sendPayload($payload); 179 | } 180 | 181 | /** 182 | * Send payload 183 | * 184 | * @access private 185 | * @throws Exception 186 | * @param string $payload 187 | * @return Exception|Client 188 | */ 189 | private function sendPayload($payload) 190 | { 191 | return ResponseParser::create() 192 | ->withReturnException($this->returnException) 193 | ->withPayload($this->httpClient->execute($payload)) 194 | ->parse(); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /vendor/fguillot/json-rpc/src/JsonRPC/Exception/AccessDeniedException.php: -------------------------------------------------------------------------------- 1 | setData($data); 37 | } 38 | 39 | /** 40 | * Attach additional information 41 | * 42 | * @access public 43 | * @param mixed $data [optional] A value that contains additional information about the error. 44 | * @return \JsonRPC\Exception\ResponseException 45 | */ 46 | public function setData($data = null) 47 | { 48 | $this->data = $data; 49 | return $this; 50 | } 51 | 52 | /** 53 | * Get additional information 54 | * 55 | * @access public 56 | * @return mixed|null 57 | */ 58 | public function getData() 59 | { 60 | return $this->data; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /vendor/fguillot/json-rpc/src/JsonRPC/Exception/ServerErrorException.php: -------------------------------------------------------------------------------- 1 | ', 42 | 'Content-Type: application/json', 43 | 'Accept: application/json', 44 | 'Connection: close', 45 | ); 46 | 47 | /** 48 | * Username for authentication 49 | * 50 | * @access private 51 | * @var string 52 | */ 53 | private $username; 54 | 55 | /** 56 | * Password for authentication 57 | * 58 | * @access private 59 | * @var string 60 | */ 61 | private $password; 62 | 63 | /** 64 | * Enable debug output to the php error log 65 | * 66 | * @access private 67 | * @var boolean 68 | */ 69 | private $debug = false; 70 | 71 | /** 72 | * Cookies 73 | * 74 | * @access private 75 | * @var array 76 | */ 77 | private $cookies = array(); 78 | 79 | /** 80 | * SSL certificates verification 81 | * 82 | * @access private 83 | * @var boolean 84 | */ 85 | private $verifySslCertificate = true; 86 | 87 | /** 88 | * SSL client certificate 89 | * 90 | * @access private 91 | * @var string 92 | */ 93 | private $sslLocalCert; 94 | 95 | /** 96 | * Callback called before the doing the request 97 | * 98 | * @access private 99 | * @var Closure 100 | */ 101 | private $beforeRequest; 102 | 103 | /** 104 | * HttpClient constructor 105 | * 106 | * @access public 107 | * @param string $url 108 | */ 109 | public function __construct($url = '') 110 | { 111 | $this->url = $url; 112 | } 113 | 114 | /** 115 | * Set URL 116 | * 117 | * @access public 118 | * @param string $url 119 | * @return $this 120 | */ 121 | public function withUrl($url) 122 | { 123 | $this->url = $url; 124 | return $this; 125 | } 126 | 127 | /** 128 | * Set username 129 | * 130 | * @access public 131 | * @param string $username 132 | * @return $this 133 | */ 134 | public function withUsername($username) 135 | { 136 | $this->username = $username; 137 | return $this; 138 | } 139 | 140 | /** 141 | * Set password 142 | * 143 | * @access public 144 | * @param string $password 145 | * @return $this 146 | */ 147 | public function withPassword($password) 148 | { 149 | $this->password = $password; 150 | return $this; 151 | } 152 | 153 | /** 154 | * Set timeout 155 | * 156 | * @access public 157 | * @param integer $timeout 158 | * @return $this 159 | */ 160 | public function withTimeout($timeout) 161 | { 162 | $this->timeout = $timeout; 163 | return $this; 164 | } 165 | 166 | /** 167 | * Set timeout 168 | * 169 | * @access public 170 | * @param array $headers 171 | * @return $this 172 | */ 173 | public function withHeaders(array $headers) 174 | { 175 | $this->headers = array_merge($this->headers, $headers); 176 | return $this; 177 | } 178 | 179 | /** 180 | * Set cookies 181 | * 182 | * @access public 183 | * @param array $cookies 184 | * @param boolean $replace 185 | */ 186 | public function withCookies(array $cookies, $replace = false) 187 | { 188 | if ($replace) { 189 | $this->cookies = $cookies; 190 | } else { 191 | $this->cookies = array_merge($this->cookies, $cookies); 192 | } 193 | } 194 | 195 | /** 196 | * Enable debug mode 197 | * 198 | * @access public 199 | * @return $this 200 | */ 201 | public function withDebug() 202 | { 203 | $this->debug = true; 204 | return $this; 205 | } 206 | 207 | /** 208 | * Disable SSL verification 209 | * 210 | * @access public 211 | * @return $this 212 | */ 213 | public function withoutSslVerification() 214 | { 215 | $this->verifySslCertificate = false; 216 | return $this; 217 | } 218 | 219 | /** 220 | * Assign a certificate to use TLS 221 | * 222 | * @access public 223 | * @return $this 224 | */ 225 | public function withSslLocalCert($path) 226 | { 227 | $this->sslLocalCert = $path; 228 | return $this; 229 | } 230 | 231 | /** 232 | * Assign a callback before the request 233 | * 234 | * @access public 235 | * @param Closure $closure 236 | * @return $this 237 | */ 238 | public function withBeforeRequestCallback(Closure $closure) 239 | { 240 | $this->beforeRequest = $closure; 241 | return $this; 242 | } 243 | 244 | /** 245 | * Get cookies 246 | * 247 | * @access public 248 | * @return array 249 | */ 250 | public function getCookies() 251 | { 252 | return $this->cookies; 253 | } 254 | 255 | /** 256 | * Do the HTTP request 257 | * 258 | * @access public 259 | * @throws ConnectionFailureException 260 | * @param string $payload 261 | * @return array 262 | */ 263 | public function execute($payload) 264 | { 265 | if (is_callable($this->beforeRequest)) { 266 | call_user_func_array($this->beforeRequest, array($this, $payload)); 267 | } 268 | 269 | $stream = fopen(trim($this->url), 'r', false, $this->buildContext($payload)); 270 | 271 | if (! is_resource($stream)) { 272 | throw new ConnectionFailureException('Unable to establish a connection'); 273 | } 274 | 275 | $metadata = stream_get_meta_data($stream); 276 | $headers = $metadata['wrapper_data']; 277 | $response = json_decode(stream_get_contents($stream), true); 278 | 279 | if ($this->debug) { 280 | error_log('==> Request: '.PHP_EOL.(is_string($payload) ? $payload : json_encode($payload, JSON_PRETTY_PRINT))); 281 | error_log('==> Headers: '.PHP_EOL.var_export($headers, true)); 282 | error_log('==> Response: '.PHP_EOL.json_encode($response, JSON_PRETTY_PRINT)); 283 | } 284 | 285 | $this->handleExceptions($headers); 286 | $this->parseCookies($headers); 287 | 288 | return $response; 289 | } 290 | 291 | /** 292 | * Prepare stream context 293 | * 294 | * @access private 295 | * @param string $payload 296 | * @return resource 297 | */ 298 | private function buildContext($payload) 299 | { 300 | $headers = $this->headers; 301 | 302 | if (! empty($this->username) && ! empty($this->password)) { 303 | $headers[] = 'Authorization: Basic '.base64_encode($this->username.':'.$this->password); 304 | } 305 | 306 | if (! empty($this->cookies)){ 307 | $cookies = array(); 308 | 309 | foreach ($this->cookies as $key => $value) { 310 | $cookies[] = $key.'='.$value; 311 | } 312 | 313 | $headers[] = 'Cookie: '.implode('; ', $cookies); 314 | } 315 | 316 | $options = array( 317 | 'http' => array( 318 | 'method' => 'POST', 319 | 'protocol_version' => 1.1, 320 | 'timeout' => $this->timeout, 321 | 'max_redirects' => 2, 322 | 'header' => implode("\r\n", $headers), 323 | 'content' => $payload, 324 | 'ignore_errors' => true, 325 | ), 326 | 'ssl' => array( 327 | 'verify_peer' => $this->verifySslCertificate, 328 | 'verify_peer_name' => $this->verifySslCertificate, 329 | ) 330 | ); 331 | 332 | if ($this->sslLocalCert !== null) { 333 | $options['ssl']['local_cert'] = $this->sslLocalCert; 334 | } 335 | 336 | return stream_context_create($options); 337 | } 338 | 339 | /** 340 | * Parse cookies from response 341 | * 342 | * @access private 343 | * @param array $headers 344 | */ 345 | private function parseCookies(array $headers) 346 | { 347 | foreach ($headers as $header) { 348 | $pos = stripos($header, 'Set-Cookie:'); 349 | 350 | if ($pos !== false) { 351 | $cookies = explode(';', substr($header, $pos + 11)); 352 | 353 | foreach ($cookies as $cookie) { 354 | $item = explode('=', $cookie); 355 | 356 | if (count($item) === 2) { 357 | $name = trim($item[0]); 358 | $value = $item[1]; 359 | $this->cookies[$name] = $value; 360 | } 361 | } 362 | } 363 | } 364 | } 365 | 366 | /** 367 | * Throw an exception according the HTTP response 368 | * 369 | * @access public 370 | * @param array $headers 371 | * @throws AccessDeniedException 372 | * @throws ServerErrorException 373 | */ 374 | public function handleExceptions(array $headers) 375 | { 376 | $exceptions = array( 377 | '401' => '\JsonRPC\Exception\AccessDeniedException', 378 | '403' => '\JsonRPC\Exception\AccessDeniedException', 379 | '404' => '\JsonRPC\Exception\ConnectionFailureException', 380 | '500' => '\JsonRPC\Exception\ServerErrorException', 381 | ); 382 | 383 | foreach ($headers as $header) { 384 | foreach ($exceptions as $code => $exception) { 385 | if (strpos($header, 'HTTP/1.0 '.$code) !== false || strpos($header, 'HTTP/1.1 '.$code) !== false) { 386 | throw new $exception('Response: '.$header); 387 | } 388 | } 389 | } 390 | } 391 | } 392 | -------------------------------------------------------------------------------- /vendor/fguillot/json-rpc/src/JsonRPC/MiddlewareHandler.php: -------------------------------------------------------------------------------- 1 | username = $username; 56 | } 57 | 58 | return $this; 59 | } 60 | 61 | /** 62 | * Set password 63 | * 64 | * @access public 65 | * @param string $password 66 | * @return $this 67 | */ 68 | public function withPassword($password) 69 | { 70 | if (! empty($password)) { 71 | $this->password = $password; 72 | } 73 | 74 | return $this; 75 | } 76 | 77 | /** 78 | * Set procedure name 79 | * 80 | * @access public 81 | * @param string $procedureName 82 | * @return $this 83 | */ 84 | public function withProcedure($procedureName) 85 | { 86 | $this->procedureName = $procedureName; 87 | return $this; 88 | } 89 | 90 | /** 91 | * Add a new middleware 92 | * 93 | * @access public 94 | * @param MiddlewareInterface $middleware 95 | * @return MiddlewareHandler 96 | */ 97 | public function withMiddleware(MiddlewareInterface $middleware) 98 | { 99 | $this->middleware[] = $middleware; 100 | return $this; 101 | } 102 | 103 | /** 104 | * Execute all middleware 105 | * 106 | * @access public 107 | */ 108 | public function execute() 109 | { 110 | foreach ($this->middleware as $middleware) { 111 | $middleware->execute($this->username, $this->password, $this->procedureName); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /vendor/fguillot/json-rpc/src/JsonRPC/MiddlewareInterface.php: -------------------------------------------------------------------------------- 1 | callbacks[$procedure] = $callback; 62 | return $this; 63 | } 64 | 65 | /** 66 | * Bind a procedure to a class 67 | * 68 | * @access public 69 | * @param string $procedure Procedure name 70 | * @param mixed $class Class name or instance 71 | * @param string $method Procedure name 72 | * @return $this 73 | */ 74 | public function withClassAndMethod($procedure, $class, $method = '') 75 | { 76 | if ($method === '') { 77 | $method = $procedure; 78 | } 79 | 80 | $this->classes[$procedure] = array($class, $method); 81 | return $this; 82 | } 83 | 84 | /** 85 | * Bind a class instance 86 | * 87 | * @access public 88 | * @param mixed $instance 89 | * @return $this 90 | */ 91 | public function withObject($instance) 92 | { 93 | $this->instances[] = $instance; 94 | return $this; 95 | } 96 | 97 | /** 98 | * Set a before method to call 99 | * 100 | * @access public 101 | * @param string $methodName 102 | * @return $this 103 | */ 104 | public function withBeforeMethod($methodName) 105 | { 106 | $this->beforeMethodName = $methodName; 107 | return $this; 108 | } 109 | 110 | /** 111 | * Execute the procedure 112 | * 113 | * @access public 114 | * @param string $procedure Procedure name 115 | * @param array $params Procedure params 116 | * @return mixed 117 | */ 118 | public function executeProcedure($procedure, array $params = array()) 119 | { 120 | if (isset($this->callbacks[$procedure])) { 121 | return $this->executeCallback($this->callbacks[$procedure], $params); 122 | } elseif (isset($this->classes[$procedure]) && method_exists($this->classes[$procedure][0], $this->classes[$procedure][1])) { 123 | return $this->executeMethod($this->classes[$procedure][0], $this->classes[$procedure][1], $params); 124 | } 125 | 126 | foreach ($this->instances as $instance) { 127 | if (method_exists($instance, $procedure)) { 128 | return $this->executeMethod($instance, $procedure, $params); 129 | } 130 | } 131 | 132 | throw new BadFunctionCallException('Unable to find the procedure'); 133 | } 134 | 135 | /** 136 | * Execute a callback 137 | * 138 | * @access public 139 | * @param Closure $callback Callback 140 | * @param array $params Procedure params 141 | * @return mixed 142 | */ 143 | public function executeCallback(Closure $callback, $params) 144 | { 145 | $reflection = new ReflectionFunction($callback); 146 | 147 | $arguments = $this->getArguments( 148 | $params, 149 | $reflection->getParameters(), 150 | $reflection->getNumberOfRequiredParameters(), 151 | $reflection->getNumberOfParameters() 152 | ); 153 | 154 | return $reflection->invokeArgs($arguments); 155 | } 156 | 157 | /** 158 | * Execute a method 159 | * 160 | * @access public 161 | * @param mixed $class Class name or instance 162 | * @param string $method Method name 163 | * @param array $params Procedure params 164 | * @return mixed 165 | */ 166 | public function executeMethod($class, $method, $params) 167 | { 168 | $instance = is_string($class) ? new $class : $class; 169 | $reflection = new ReflectionMethod($class, $method); 170 | 171 | $this->executeBeforeMethod($instance, $method); 172 | 173 | $arguments = $this->getArguments( 174 | $params, 175 | $reflection->getParameters(), 176 | $reflection->getNumberOfRequiredParameters(), 177 | $reflection->getNumberOfParameters() 178 | ); 179 | 180 | return $reflection->invokeArgs($instance, $arguments); 181 | } 182 | 183 | /** 184 | * Execute before method if defined 185 | * 186 | * @access public 187 | * @param mixed $object 188 | * @param string $method 189 | */ 190 | public function executeBeforeMethod($object, $method) 191 | { 192 | if ($this->beforeMethodName !== '' && method_exists($object, $this->beforeMethodName)) { 193 | call_user_func_array(array($object, $this->beforeMethodName), array($method)); 194 | } 195 | } 196 | 197 | /** 198 | * Get procedure arguments 199 | * 200 | * @access public 201 | * @param array $requestParams Incoming arguments 202 | * @param array $methodParams Procedure arguments 203 | * @param integer $nbRequiredParams Number of required parameters 204 | * @param integer $nbMaxParams Maximum number of parameters 205 | * @return array 206 | */ 207 | public function getArguments(array $requestParams, array $methodParams, $nbRequiredParams, $nbMaxParams) 208 | { 209 | $nbParams = count($requestParams); 210 | 211 | if ($nbParams < $nbRequiredParams) { 212 | throw new InvalidArgumentException('Wrong number of arguments'); 213 | } 214 | 215 | if ($nbParams > $nbMaxParams) { 216 | throw new InvalidArgumentException('Too many arguments'); 217 | } 218 | 219 | if ($this->isPositionalArguments($requestParams)) { 220 | return $requestParams; 221 | } 222 | 223 | return $this->getNamedArguments($requestParams, $methodParams); 224 | } 225 | 226 | /** 227 | * Return true if we have positional parameters 228 | * 229 | * @access public 230 | * @param array $request_params Incoming arguments 231 | * @return bool 232 | */ 233 | public function isPositionalArguments(array $request_params) 234 | { 235 | return array_keys($request_params) === range(0, count($request_params) - 1); 236 | } 237 | 238 | /** 239 | * Get named arguments 240 | * 241 | * @access public 242 | * @param array $requestParams Incoming arguments 243 | * @param array $methodParams Procedure arguments 244 | * @return array 245 | */ 246 | public function getNamedArguments(array $requestParams, array $methodParams) 247 | { 248 | $params = array(); 249 | 250 | foreach ($methodParams as $p) { 251 | $name = $p->getName(); 252 | 253 | if (isset($requestParams[$name])) { 254 | $params[$name] = $requestParams[$name]; 255 | } elseif ($p->isDefaultValueAvailable()) { 256 | $params[$name] = $p->getDefaultValue(); 257 | } else { 258 | throw new InvalidArgumentException('Missing argument: '.$name); 259 | } 260 | } 261 | 262 | return $params; 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /vendor/fguillot/json-rpc/src/JsonRPC/Request/BatchRequestParser.php: -------------------------------------------------------------------------------- 1 | payload as $payload) { 24 | $responses[] = RequestParser::create() 25 | ->withPayload($payload) 26 | ->withProcedureHandler($this->procedureHandler) 27 | ->withMiddlewareHandler($this->middlewareHandler) 28 | ->withLocalException($this->localExceptions) 29 | ->parse(); 30 | } 31 | 32 | $responses = array_filter($responses); 33 | return empty($responses) ? '' : '['.implode(',', $responses).']'; 34 | } 35 | 36 | /** 37 | * Return true if we have a batch request 38 | * 39 | * ex : [ 40 | * 0 => '...', 41 | * 1 => '...', 42 | * 2 => '...', 43 | * 3 => '...', 44 | * ] 45 | * 46 | * @static 47 | * @access public 48 | * @param array $payload 49 | * @return bool 50 | */ 51 | public static function isBatchRequest(array $payload) 52 | { 53 | return array_keys($payload) === range(0, count($payload) - 1); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /vendor/fguillot/json-rpc/src/JsonRPC/Request/RequestBuilder.php: -------------------------------------------------------------------------------- 1 | id = $id; 67 | return $this; 68 | } 69 | 70 | /** 71 | * Set method 72 | * 73 | * @access public 74 | * @param string $procedure 75 | * @return RequestBuilder 76 | */ 77 | public function withProcedure($procedure) 78 | { 79 | $this->procedure = $procedure; 80 | return $this; 81 | } 82 | 83 | /** 84 | * Set parameters 85 | * 86 | * @access public 87 | * @param array $params 88 | * @return RequestBuilder 89 | */ 90 | public function withParams(array $params) 91 | { 92 | $this->params = $params; 93 | return $this; 94 | } 95 | 96 | /** 97 | * Set additional request attributes 98 | * 99 | * @access public 100 | * @param array $reqattrs 101 | * @return RequestBuilder 102 | */ 103 | public function withRequestAttributes(array $reqattrs) 104 | { 105 | $this->reqattrs = $reqattrs; 106 | return $this; 107 | } 108 | 109 | /** 110 | * Build the payload 111 | * 112 | * @access public 113 | * @return string 114 | */ 115 | public function build() 116 | { 117 | $payload = array_merge_recursive($this->reqattrs, array( 118 | 'jsonrpc' => '2.0', 119 | 'method' => $this->procedure, 120 | 'id' => $this->id ?: mt_rand(), 121 | )); 122 | 123 | if (! empty($this->params)) { 124 | $payload['params'] = $this->params; 125 | } 126 | 127 | return json_encode($payload); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /vendor/fguillot/json-rpc/src/JsonRPC/Request/RequestParser.php: -------------------------------------------------------------------------------- 1 | payload = $payload; 80 | return $this; 81 | } 82 | 83 | /** 84 | * Exception classes that should not be relayed to the client 85 | * 86 | * @access public 87 | * @param mixed $exception 88 | * @return $this 89 | */ 90 | public function withLocalException($exception) 91 | { 92 | if (is_array($exception)) { 93 | $this->localExceptions = array_merge($this->localExceptions, $exception); 94 | } else { 95 | $this->localExceptions[] = $exception; 96 | } 97 | 98 | return $this; 99 | } 100 | 101 | /** 102 | * Set procedure handler 103 | * 104 | * @access public 105 | * @param ProcedureHandler $procedureHandler 106 | * @return $this 107 | */ 108 | public function withProcedureHandler(ProcedureHandler $procedureHandler) 109 | { 110 | $this->procedureHandler = $procedureHandler; 111 | return $this; 112 | } 113 | 114 | /** 115 | * Set middleware handler 116 | * 117 | * @access public 118 | * @param MiddlewareHandler $middlewareHandler 119 | * @return $this 120 | */ 121 | public function withMiddlewareHandler(MiddlewareHandler $middlewareHandler) 122 | { 123 | $this->middlewareHandler = $middlewareHandler; 124 | return $this; 125 | } 126 | 127 | /** 128 | * Parse incoming request 129 | * 130 | * @access public 131 | * @return string 132 | * @throws AccessDeniedException 133 | * @throws AuthenticationFailureException 134 | */ 135 | public function parse() 136 | { 137 | try { 138 | 139 | JsonFormatValidator::validate($this->payload); 140 | RpcFormatValidator::validate($this->payload); 141 | 142 | $this->middlewareHandler 143 | ->withProcedure($this->payload['method']) 144 | ->execute(); 145 | 146 | $result = $this->procedureHandler->executeProcedure( 147 | $this->payload['method'], 148 | empty($this->payload['params']) ? array() : $this->payload['params'] 149 | ); 150 | 151 | if (! $this->isNotification()) { 152 | return ResponseBuilder::create() 153 | ->withId($this->payload['id']) 154 | ->withResult($result) 155 | ->build(); 156 | } 157 | } catch (Exception $e) { 158 | return $this->handleExceptions($e); 159 | } 160 | 161 | return ''; 162 | } 163 | 164 | /** 165 | * Handle exceptions 166 | * 167 | * @access protected 168 | * @param Exception $e 169 | * @return string 170 | * @throws Exception 171 | */ 172 | protected function handleExceptions(Exception $e) 173 | { 174 | foreach ($this->localExceptions as $exception) { 175 | if ($e instanceof $exception) { 176 | throw $e; 177 | } 178 | } 179 | 180 | if ($e instanceof InvalidJsonRpcFormatException || ! $this->isNotification()) { 181 | return ResponseBuilder::create() 182 | ->withId(isset($this->payload['id']) ? $this->payload['id'] : null) 183 | ->withException($e) 184 | ->build(); 185 | } 186 | 187 | return ''; 188 | } 189 | 190 | /** 191 | * Return true if the message is a notification 192 | * 193 | * @access protected 194 | * @return bool 195 | */ 196 | protected function isNotification() 197 | { 198 | return is_array($this->payload) && !isset($this->payload['id']); 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /vendor/fguillot/json-rpc/src/JsonRPC/Response/ResponseBuilder.php: -------------------------------------------------------------------------------- 1 | 'application/json', 72 | ); 73 | 74 | /** 75 | * HTTP status 76 | * 77 | * @access protected 78 | * @var string 79 | */ 80 | protected $status; 81 | 82 | /** 83 | * Exception 84 | * 85 | * @access protected 86 | * @var ResponseException 87 | */ 88 | protected $exception; 89 | 90 | /** 91 | * Get new object instance 92 | * 93 | * @static 94 | * @access public 95 | * @return ResponseBuilder 96 | */ 97 | public static function create() 98 | { 99 | return new static(); 100 | } 101 | 102 | /** 103 | * Set id 104 | * 105 | * @access public 106 | * @param mixed $id 107 | * @return $this 108 | */ 109 | public function withId($id) 110 | { 111 | $this->id = $id; 112 | return $this; 113 | } 114 | 115 | /** 116 | * Set result 117 | * 118 | * @access public 119 | * @param mixed $result 120 | * @return $this 121 | */ 122 | public function withResult($result) 123 | { 124 | $this->result = $result; 125 | return $this; 126 | } 127 | 128 | /** 129 | * Set error 130 | * 131 | * @access public 132 | * @param integer $code 133 | * @param string $message 134 | * @param string $data 135 | * @return $this 136 | */ 137 | public function withError($code, $message, $data = '') 138 | { 139 | $this->errorCode = $code; 140 | $this->errorMessage = $message; 141 | $this->errorData = $data; 142 | return $this; 143 | } 144 | 145 | /** 146 | * Set exception 147 | * 148 | * @access public 149 | * @param Exception $exception 150 | * @return $this 151 | */ 152 | public function withException(Exception $exception) 153 | { 154 | $this->exception = $exception; 155 | return $this; 156 | } 157 | 158 | /** 159 | * Add HTTP header 160 | * 161 | * @access public 162 | * @param string $name 163 | * @param string $value 164 | * @return $this 165 | */ 166 | public function withHeader($name, $value) 167 | { 168 | $this->headers[$name] = $value; 169 | return $this; 170 | } 171 | 172 | /** 173 | * Add HTTP Status 174 | * 175 | * @access public 176 | * @param string $status 177 | * @return $this 178 | */ 179 | public function withStatus($status) 180 | { 181 | $this->status = $status; 182 | return $this; 183 | } 184 | 185 | /** 186 | * Get status 187 | * 188 | * @access public 189 | * @return string 190 | */ 191 | public function getStatus() 192 | { 193 | return $this->status; 194 | } 195 | 196 | /** 197 | * Get headers 198 | * 199 | * @access public 200 | * @return string[] 201 | */ 202 | public function getHeaders() 203 | { 204 | return $this->headers; 205 | } 206 | 207 | /** 208 | * Build response 209 | * 210 | * @access public 211 | * @return string 212 | */ 213 | public function build() 214 | { 215 | $options = 0; 216 | if (defined('JSON_UNESCAPED_SLASHES')) { 217 | $options |= JSON_UNESCAPED_SLASHES; 218 | } 219 | if (defined('JSON_UNESCAPED_UNICODE')) { 220 | $options |= JSON_UNESCAPED_UNICODE; 221 | } 222 | $encodedResponse = json_encode($this->buildResponse(), $options); 223 | JsonEncodingValidator::validate(); 224 | 225 | return $encodedResponse; 226 | } 227 | 228 | /** 229 | * Send HTTP headers 230 | * 231 | * @access public 232 | * @return $this 233 | */ 234 | public function sendHeaders() 235 | { 236 | if (! empty($this->status)) { 237 | header($this->status); 238 | } 239 | 240 | foreach ($this->headers as $name => $value) { 241 | header($name.': '.$value); 242 | } 243 | 244 | return $this; 245 | } 246 | 247 | /** 248 | * Build response payload 249 | * 250 | * @access protected 251 | * @return array 252 | */ 253 | protected function buildResponse() 254 | { 255 | $response = array('jsonrpc' => '2.0'); 256 | $this->handleExceptions(); 257 | 258 | if (! empty($this->errorMessage)) { 259 | $response['error'] = $this->buildErrorResponse(); 260 | } else { 261 | $response['result'] = $this->result; 262 | } 263 | 264 | $response['id'] = $this->id; 265 | return $response; 266 | } 267 | 268 | /** 269 | * Build response error payload 270 | * 271 | * @access protected 272 | * @return array 273 | */ 274 | protected function buildErrorResponse() 275 | { 276 | $response = array( 277 | 'code' => $this->errorCode, 278 | 'message' => $this->errorMessage, 279 | ); 280 | 281 | if (! empty($this->errorData)) { 282 | $response['data'] = $this->errorData; 283 | } 284 | 285 | return $response; 286 | } 287 | 288 | /** 289 | * Transform exceptions to JSON-RPC errors 290 | * 291 | * @access protected 292 | */ 293 | protected function handleExceptions() 294 | { 295 | try { 296 | if ($this->exception instanceof Exception) { 297 | throw $this->exception; 298 | } 299 | } catch (InvalidJsonFormatException $e) { 300 | $this->errorCode = -32700; 301 | $this->errorMessage = 'Parse error'; 302 | $this->id = null; 303 | } catch (InvalidJsonRpcFormatException $e) { 304 | $this->errorCode = -32600; 305 | $this->errorMessage = 'Invalid Request'; 306 | $this->id = null; 307 | } catch (BadFunctionCallException $e) { 308 | $this->errorCode = -32601; 309 | $this->errorMessage = 'Method not found'; 310 | } catch (InvalidArgumentException $e) { 311 | $this->errorCode = -32602; 312 | $this->errorMessage = 'Invalid params'; 313 | } catch (ResponseEncodingFailureException $e) { 314 | $this->errorCode = -32603; 315 | $this->errorMessage = 'Internal error'; 316 | $this->errorData = $this->exception->getMessage(); 317 | } catch (AuthenticationFailureException $e) { 318 | $this->errorCode = 401; 319 | $this->errorMessage = 'Unauthorized'; 320 | $this->status = 'HTTP/1.0 401 Unauthorized'; 321 | $this->withHeader('WWW-Authenticate', 'Basic realm="JsonRPC"'); 322 | } catch (AccessDeniedException $e) { 323 | $this->errorCode = 403; 324 | $this->errorMessage = 'Forbidden'; 325 | $this->status = 'HTTP/1.0 403 Forbidden'; 326 | } catch (ResponseException $e) { 327 | $this->errorCode = $this->exception->getCode(); 328 | $this->errorMessage = $this->exception->getMessage(); 329 | $this->errorData = $this->exception->getData(); 330 | } catch (Exception $e) { 331 | $this->errorCode = $this->exception->getCode(); 332 | $this->errorMessage = $this->exception->getMessage(); 333 | } 334 | } 335 | } 336 | -------------------------------------------------------------------------------- /vendor/fguillot/json-rpc/src/JsonRPC/Response/ResponseParser.php: -------------------------------------------------------------------------------- 1 | returnException = $returnException; 57 | return $this; 58 | } 59 | 60 | /** 61 | * Set payload 62 | * 63 | * @access public 64 | * @param mixed $payload 65 | * @return $this 66 | */ 67 | public function withPayload($payload) 68 | { 69 | $this->payload = $payload; 70 | return $this; 71 | } 72 | 73 | /** 74 | * Parse response 75 | * 76 | * @return array|Exception|null 77 | * @throws InvalidJsonFormatException 78 | * @throws BadFunctionCallException 79 | * @throws InvalidJsonRpcFormatException 80 | * @throws InvalidArgumentException 81 | * @throws Exception 82 | * @throws ResponseException 83 | */ 84 | public function parse() 85 | { 86 | JsonFormatValidator::validate($this->payload); 87 | 88 | if ($this->isBatchResponse()) { 89 | $results = array(); 90 | 91 | foreach ($this->payload as $response) { 92 | $results[] = self::create() 93 | ->withReturnException($this->returnException) 94 | ->withPayload($response) 95 | ->parse(); 96 | } 97 | 98 | return $results; 99 | } 100 | 101 | if (isset($this->payload['error']['code'])) { 102 | try { 103 | $this->handleExceptions(); 104 | } catch (Exception $e) { 105 | if ($this->returnException) { 106 | return $e; 107 | } 108 | throw $e; 109 | } 110 | } 111 | 112 | return isset($this->payload['result']) ? $this->payload['result'] : null; 113 | } 114 | 115 | /** 116 | * Handle exceptions 117 | * 118 | * @access private 119 | * @throws InvalidJsonFormatException 120 | * @throws InvalidJsonRpcFormatException 121 | * @throws ResponseException 122 | */ 123 | private function handleExceptions() 124 | { 125 | switch ($this->payload['error']['code']) { 126 | case -32700: 127 | throw new InvalidJsonFormatException('Parse error: '.$this->payload['error']['message']); 128 | case -32600: 129 | throw new InvalidJsonRpcFormatException('Invalid Request: '.$this->payload['error']['message']); 130 | case -32601: 131 | throw new BadFunctionCallException('Procedure not found: '.$this->payload['error']['message']); 132 | case -32602: 133 | throw new InvalidArgumentException('Invalid arguments: '.$this->payload['error']['message']); 134 | default: 135 | throw new ResponseException( 136 | $this->payload['error']['message'], 137 | $this->payload['error']['code'], 138 | null, 139 | isset($this->payload['error']['data']) ? $this->payload['error']['data'] : null 140 | ); 141 | } 142 | } 143 | 144 | /** 145 | * Return true if we have a batch response 146 | * 147 | * @access private 148 | * @return boolean 149 | */ 150 | private function isBatchResponse() 151 | { 152 | return array_keys($this->payload) === range(0, count($this->payload) - 1); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /vendor/fguillot/json-rpc/src/JsonRPC/Server.php: -------------------------------------------------------------------------------- 1 | payload = json_decode($request, true); 142 | } else { 143 | $this->payload = json_decode(file_get_contents('php://input'), true); 144 | } 145 | 146 | $this->serverVariable = $server ?: $_SERVER; 147 | $this->responseBuilder = $responseBuilder ?: ResponseBuilder::create(); 148 | $this->requestParser = $requestParser ?: RequestParser::create(); 149 | $this->batchRequestParser = $batchRequestParser ?: BatchRequestParser::create(); 150 | $this->procedureHandler = $procedureHandler ?: new ProcedureHandler(); 151 | $this->middlewareHandler = $middlewareHandler ?: new MiddlewareHandler(); 152 | } 153 | 154 | /** 155 | * Define alternative authentication header 156 | * 157 | * @access public 158 | * @param string $header Header name 159 | * @return $this 160 | */ 161 | public function setAuthenticationHeader($header) 162 | { 163 | if (! empty($header)) { 164 | $header = 'HTTP_'.str_replace('-', '_', strtoupper($header)); 165 | $value = $this->getServerVariable($header); 166 | 167 | if (! empty($value)) { 168 | list($this->username, $this->password) = explode(':', base64_decode($value)); 169 | } 170 | } 171 | 172 | return $this; 173 | } 174 | 175 | /** 176 | * Get ProcedureHandler 177 | * 178 | * @access public 179 | * @return ProcedureHandler 180 | */ 181 | public function getProcedureHandler() 182 | { 183 | return $this->procedureHandler; 184 | } 185 | 186 | /** 187 | * Get MiddlewareHandler 188 | * 189 | * @access public 190 | * @return MiddlewareHandler 191 | */ 192 | public function getMiddlewareHandler() 193 | { 194 | return $this->middlewareHandler; 195 | } 196 | 197 | /** 198 | * Get username 199 | * 200 | * @access public 201 | * @return string 202 | */ 203 | public function getUsername() 204 | { 205 | return $this->username ?: $this->getServerVariable('PHP_AUTH_USER'); 206 | } 207 | 208 | /** 209 | * Get password 210 | * 211 | * @access public 212 | * @return string 213 | */ 214 | public function getPassword() 215 | { 216 | return $this->password ?: $this->getServerVariable('PHP_AUTH_PW'); 217 | } 218 | 219 | /** 220 | * IP based client restrictions 221 | * 222 | * @access public 223 | * @param array $hosts List of hosts 224 | * @return $this 225 | */ 226 | public function allowHosts(array $hosts) 227 | { 228 | $this->hosts = $hosts; 229 | return $this; 230 | } 231 | 232 | /** 233 | * HTTP Basic authentication 234 | * 235 | * @access public 236 | * @param array $users Dictionary of username/password 237 | * @return $this 238 | */ 239 | public function authentication(array $users) 240 | { 241 | $this->users = $users; 242 | return $this; 243 | } 244 | 245 | /** 246 | * Register a new procedure 247 | * 248 | * @access public 249 | * @deprecated Use $server->getProcedureHandler()->withCallback($procedure, $callback) 250 | * @param string $procedure Procedure name 251 | * @param closure $callback Callback 252 | * @return $this 253 | */ 254 | public function register($procedure, Closure $callback) 255 | { 256 | $this->procedureHandler->withCallback($procedure, $callback); 257 | return $this; 258 | } 259 | 260 | /** 261 | * Bind a procedure to a class 262 | * 263 | * @access public 264 | * @deprecated Use $server->getProcedureHandler()->withClassAndMethod($procedure, $class, $method); 265 | * @param string $procedure Procedure name 266 | * @param mixed $class Class name or instance 267 | * @param string $method Procedure name 268 | * @return $this 269 | */ 270 | public function bind($procedure, $class, $method = '') 271 | { 272 | $this->procedureHandler->withClassAndMethod($procedure, $class, $method); 273 | return $this; 274 | } 275 | 276 | /** 277 | * Bind a class instance 278 | * 279 | * @access public 280 | * @deprecated Use $server->getProcedureHandler()->withObject($instance); 281 | * @param mixed $instance Instance name 282 | * @return $this 283 | */ 284 | public function attach($instance) 285 | { 286 | $this->procedureHandler->withObject($instance); 287 | return $this; 288 | } 289 | 290 | /** 291 | * Exception classes that should not be relayed to the client 292 | * 293 | * @access public 294 | * @param Exception|string $exception 295 | * @return $this 296 | */ 297 | public function withLocalException($exception) 298 | { 299 | $this->localExceptions[] = $exception; 300 | return $this; 301 | } 302 | 303 | /** 304 | * Parse incoming requests 305 | * 306 | * @access public 307 | * @return string 308 | */ 309 | public function execute() 310 | { 311 | try { 312 | JsonFormatValidator::validate($this->payload); 313 | HostValidator::validate($this->hosts, $this->getServerVariable('REMOTE_ADDR')); 314 | UserValidator::validate($this->users, $this->getUsername(), $this->getPassword()); 315 | 316 | $this->middlewareHandler 317 | ->withUsername($this->getUsername()) 318 | ->withPassword($this->getPassword()) 319 | ; 320 | 321 | $response = $this->parseRequest(); 322 | 323 | } catch (Exception $e) { 324 | $response = $this->handleExceptions($e); 325 | } 326 | 327 | $this->responseBuilder->sendHeaders(); 328 | return $response; 329 | } 330 | 331 | /** 332 | * Handle exceptions 333 | * 334 | * @access protected 335 | * @param Exception $e 336 | * @return string 337 | * @throws Exception 338 | */ 339 | protected function handleExceptions(Exception $e) 340 | { 341 | foreach ($this->localExceptions as $exception) { 342 | if ($e instanceof $exception) { 343 | throw $e; 344 | } 345 | } 346 | 347 | return $this->responseBuilder->withException($e)->build(); 348 | } 349 | 350 | /** 351 | * Parse incoming request 352 | * 353 | * @access protected 354 | * @return string 355 | */ 356 | protected function parseRequest() 357 | { 358 | if (BatchRequestParser::isBatchRequest($this->payload)) { 359 | return $this->batchRequestParser 360 | ->withPayload($this->payload) 361 | ->withProcedureHandler($this->procedureHandler) 362 | ->withMiddlewareHandler($this->middlewareHandler) 363 | ->withLocalException($this->localExceptions) 364 | ->parse(); 365 | } 366 | 367 | return $this->requestParser 368 | ->withPayload($this->payload) 369 | ->withProcedureHandler($this->procedureHandler) 370 | ->withMiddlewareHandler($this->middlewareHandler) 371 | ->withLocalException($this->localExceptions) 372 | ->parse(); 373 | } 374 | 375 | /** 376 | * Check existence and get value of server variable 377 | * 378 | * @access protected 379 | * @param string $variable 380 | * @return string|null 381 | */ 382 | protected function getServerVariable($variable) 383 | { 384 | return isset($this->serverVariable[$variable]) ? $this->serverVariable[$variable] : null; 385 | } 386 | } 387 | -------------------------------------------------------------------------------- /vendor/fguillot/json-rpc/src/JsonRPC/Validator/HostValidator.php: -------------------------------------------------------------------------------- 1 | N.b. A note on Ubuntu 14.04 (probably other Debian-based / Apt managed systems), the install of php5-imap does not enable the extension for CLI (possibly others as well), which can cause composer to report fetch requires ext-imap 14 | ``` 15 | sudo ln -s /etc/php5/mods-available/imap.ini /etc/php5/cli/conf.d/30-imap.ini 16 | ``` 17 | 18 | ### Composer 19 | 20 | Installing Fetch can be done through a variety of methods, although Composer is 21 | recommended. 22 | 23 | Until Fetch reaches a stable API with version 1.0 it is recommended that you 24 | review changes before even Minor updates, although bug fixes will always be 25 | backwards compatible. 26 | 27 | ``` 28 | "require": { 29 | "tedivm/fetch": "0.6.*" 30 | } 31 | ``` 32 | 33 | ### Pear 34 | 35 | Fetch is also available through Pear. 36 | 37 | ``` 38 | $ pear channel-discover pear.tedivm.com 39 | $ pear install tedivm/Fetch 40 | ``` 41 | 42 | ### Github 43 | 44 | Releases of Fetch are available on [Github](https://github.com/tedious/Fetch/releases). 45 | 46 | 47 | ## Sample Usage 48 | 49 | This is just a simple code to show how to access messages by using Fetch. It uses Fetch 50 | own autoload, but it can (and should be, if applicable) replaced with the one generated 51 | by composer. 52 | 53 | 54 | $server = new \Fetch\Server('imap.example.com', 993); 55 | $server->setAuthentication('dummy', 'dummy'); 56 | 57 | 58 | $messages = $server->getMessages(); 59 | /** @var $message \Fetch\Message */ 60 | foreach ($messages as $message) { 61 | echo "Subject: {$message->getSubject()}\nBody: {$message->getMessageBody()}\n"; 62 | } 63 | 64 | 65 | ## License 66 | 67 | Fetch is licensed under the BSD License. See the LICENSE file for details. 68 | -------------------------------------------------------------------------------- /vendor/tedivm/fetch/autoload.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | spl_autoload_register(function ($class) { 13 | $base = '/src/'; 14 | 15 | if (strpos($class, 'Fetch\Test') === 0) { 16 | $base = '/tests/'; 17 | } 18 | 19 | $file = __DIR__.$base.strtr($class, '\\', '/').'.php'; 20 | if (file_exists($file)) { 21 | require $file; 22 | 23 | return true; 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /vendor/tedivm/fetch/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tedivm/fetch", 3 | "description": "A PHP IMAP Library", 4 | "keywords": ["email","imap","pop3"], 5 | "homepage": "http://github.com/tedious/Fetch", 6 | "type": "library", 7 | "license": "BSD-3-Clause", 8 | "authors": [ 9 | { 10 | "name": "Robert Hafner", 11 | "email": "tedivm@tedivm.com" 12 | } 13 | ], 14 | "require": { 15 | "php": ">=5.3.0", 16 | "ext-imap": "*" 17 | }, 18 | "require-dev": { 19 | "tedivm/dovecottesting": "1.2.3", 20 | "phpunit/phpunit": "4.2.*", 21 | "fabpot/php-cs-fixer": "0.5.*", 22 | "satooshi/php-coveralls": "dev-master" 23 | 24 | }, 25 | "autoload": { 26 | "psr-0": {"Fetch": "src/"} 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /vendor/tedivm/fetch/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | ./tests 17 | 18 | 19 | 20 | 21 | ./src/Fetch/ 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /vendor/tedivm/fetch/src/Fetch/Attachment.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Fetch; 13 | 14 | /** 15 | * This library is a wrapper around the Imap library functions included in php. This class wraps around an attachment 16 | * in a message, allowing developers to easily save or display attachments. 17 | * 18 | * @package Fetch 19 | * @author Robert Hafner 20 | */ 21 | class Attachment 22 | { 23 | 24 | /** 25 | * This is the structure object for the piece of the message body that the attachment is located it. 26 | * 27 | * @var \stdClass 28 | */ 29 | protected $structure; 30 | 31 | /** 32 | * This is the unique identifier for the message this attachment belongs to. 33 | * 34 | * @var int 35 | */ 36 | protected $messageId; 37 | 38 | /** 39 | * This is the ImapResource. 40 | * 41 | * @var resource 42 | */ 43 | protected $imapStream; 44 | 45 | /** 46 | * This is the id pointing to the section of the message body that contains the attachment. 47 | * 48 | * @var int 49 | */ 50 | protected $partId; 51 | 52 | /** 53 | * This is the attachments filename. 54 | * 55 | * @var string 56 | */ 57 | protected $filename; 58 | 59 | /** 60 | * This is the size of the attachment. 61 | * 62 | * @var int 63 | */ 64 | protected $size; 65 | 66 | /** 67 | * This stores the data of the attachment so it doesn't have to be retrieved from the server multiple times. It is 68 | * only populated if the getData() function is called and should not be directly used. 69 | * 70 | * @internal 71 | * @var array 72 | */ 73 | protected $data; 74 | 75 | /** 76 | * This function takes in an ImapMessage, the structure object for the particular piece of the message body that the 77 | * attachment is located at, and the identifier for that body part. As a general rule you should not be creating 78 | * instances of this yourself, but rather should get them from an ImapMessage class. 79 | * 80 | * @param Message $message 81 | * @param \stdClass $structure 82 | * @param string $partIdentifier 83 | */ 84 | public function __construct(Message $message, $structure, $partIdentifier = null) 85 | { 86 | $this->messageId = $message->getUid(); 87 | $this->imapStream = $message->getImapBox()->getImapStream(); 88 | $this->structure = $structure; 89 | 90 | if (isset($partIdentifier)) 91 | $this->partId = $partIdentifier; 92 | 93 | $parameters = Message::getParametersFromStructure($structure); 94 | 95 | if (isset($parameters['filename'])) { 96 | $this->filename = imap_utf8($parameters['filename']); 97 | } elseif (isset($parameters['name'])) { 98 | $this->filename = imap_utf8($parameters['name']); 99 | } 100 | 101 | $this->size = $structure->bytes; 102 | 103 | $this->mimeType = Message::typeIdToString($structure->type); 104 | 105 | if (isset($structure->subtype)) 106 | $this->mimeType .= '/' . strtolower($structure->subtype); 107 | 108 | $this->encoding = $structure->encoding; 109 | } 110 | 111 | /** 112 | * This function returns the data of the attachment. Combined with getMimeType() it can be used to directly output 113 | * data to a browser. 114 | * 115 | * @return string 116 | */ 117 | public function getData() 118 | { 119 | if (!isset($this->data)) { 120 | $messageBody = isset($this->partId) ? 121 | imap_fetchbody($this->imapStream, $this->messageId, $this->partId, FT_UID) 122 | : imap_body($this->imapStream, $this->messageId, FT_UID); 123 | 124 | $messageBody = Message::decode($messageBody, $this->encoding); 125 | $this->data = $messageBody; 126 | } 127 | 128 | return $this->data; 129 | } 130 | 131 | /** 132 | * This returns the filename of the attachment, or false if one isn't given. 133 | * 134 | * @return string 135 | */ 136 | public function getFileName() 137 | { 138 | return (isset($this->filename)) ? $this->filename : false; 139 | } 140 | 141 | /** 142 | * This function returns the mimetype of the attachment. 143 | * 144 | * @return string 145 | */ 146 | public function getMimeType() 147 | { 148 | return $this->mimeType; 149 | } 150 | 151 | /** 152 | * This returns the size of the attachment. 153 | * 154 | * @return int 155 | */ 156 | public function getSize() 157 | { 158 | return $this->size; 159 | } 160 | 161 | /** 162 | * This function returns the object that contains the structure of this attachment. 163 | * 164 | * @return \stdClass 165 | */ 166 | public function getStructure() 167 | { 168 | return $this->structure; 169 | } 170 | 171 | /** 172 | * This function saves the attachment to the passed directory, keeping the original name of the file. 173 | * 174 | * @param string $path 175 | * @return bool 176 | */ 177 | public function saveToDirectory($path) 178 | { 179 | $path = rtrim($path, '/') . '/'; 180 | 181 | if (is_dir($path)) 182 | return $this->saveAs($path . $this->getFileName()); 183 | 184 | return false; 185 | } 186 | 187 | /** 188 | * This function saves the attachment to the exact specified location. 189 | * 190 | * @param string $path 191 | * @return bool 192 | */ 193 | public function saveAs($path) 194 | { 195 | $dirname = dirname($path); 196 | if (file_exists($path)) { 197 | if (!is_writable($path)) { 198 | return false; 199 | } 200 | } elseif (!is_dir($dirname) || !is_writable($dirname)) { 201 | return false; 202 | } 203 | 204 | if (($filePointer = fopen($path, 'w')) == false) { 205 | return false; 206 | } 207 | 208 | switch ($this->encoding) { 209 | case 3: //base64 210 | $streamFilter = stream_filter_append($filePointer, 'convert.base64-decode', STREAM_FILTER_WRITE); 211 | break; 212 | 213 | case 4: //quoted-printable 214 | $streamFilter = stream_filter_append($filePointer, 'convert.quoted-printable-decode', STREAM_FILTER_WRITE); 215 | break; 216 | 217 | default: 218 | $streamFilter = null; 219 | } 220 | 221 | // Fix an issue causing server to throw an error 222 | // See: https://github.com/tedious/Fetch/issues/74 for more details 223 | $fetch = imap_fetchbody($this->imapStream, $this->messageId, $this->partId ?: 1, FT_UID); 224 | $result = imap_savebody($this->imapStream, $filePointer, $this->messageId, $this->partId ?: 1, FT_UID); 225 | 226 | if ($streamFilter) { 227 | stream_filter_remove($streamFilter); 228 | } 229 | 230 | fclose($filePointer); 231 | 232 | return $result; 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /vendor/tedivm/fetch/src/Fetch/Message.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Fetch; 13 | 14 | /** 15 | * This library is a wrapper around the Imap library functions included in php. This class represents a single email 16 | * message as retrieved from the Imap. 17 | * 18 | * @package Fetch 19 | * @author Robert Hafner 20 | */ 21 | class Message 22 | { 23 | /** 24 | * This is the connection/mailbox class that the email came from. 25 | * 26 | * @var Server 27 | */ 28 | protected $imapConnection; 29 | 30 | /** 31 | * This is the unique identifier for the message. This corresponds to the imap "uid", which we use instead of the 32 | * sequence number. 33 | * 34 | * @var int 35 | */ 36 | protected $uid; 37 | 38 | /** 39 | * This is a reference to the Imap stream generated by 'imap_open'. 40 | * 41 | * @var resource 42 | */ 43 | protected $imapStream; 44 | 45 | /** 46 | * This as an string which contains raw header information for the message. 47 | * 48 | * @var string 49 | */ 50 | protected $rawHeaders; 51 | 52 | /** 53 | * This as an object which contains header information for the message. 54 | * 55 | * @var \stdClass 56 | */ 57 | protected $headers; 58 | 59 | /** 60 | * This is an object which contains various status messages and other information about the message. 61 | * 62 | * @var \stdClass 63 | */ 64 | protected $messageOverview; 65 | 66 | /** 67 | * This is an object which contains information about the structure of the message body. 68 | * 69 | * @var \stdClass 70 | */ 71 | protected $structure; 72 | 73 | /** 74 | * This is an array with the index being imap flags and the value being a boolean specifying whether that flag is 75 | * set or not. 76 | * 77 | * @var array 78 | */ 79 | protected $status = array(); 80 | 81 | /** 82 | * This is an array of the various imap flags that can be set. 83 | * 84 | * @var string 85 | */ 86 | protected static $flagTypes = array(self::FLAG_RECENT, self::FLAG_FLAGGED, self::FLAG_ANSWERED, self::FLAG_DELETED, self::FLAG_SEEN, self::FLAG_DRAFT); 87 | 88 | /** 89 | * This holds the plantext email message. 90 | * 91 | * @var string 92 | */ 93 | protected $plaintextMessage; 94 | 95 | /** 96 | * This holds the html version of the email. 97 | * 98 | * @var string 99 | */ 100 | protected $htmlMessage; 101 | 102 | /** 103 | * This is the date the email was sent. 104 | * 105 | * @var int 106 | */ 107 | protected $date; 108 | 109 | /** 110 | * This is the subject of the email. 111 | * 112 | * @var string 113 | */ 114 | protected $subject; 115 | 116 | /** 117 | * This is the size of the email. 118 | * 119 | * @var int 120 | */ 121 | protected $size; 122 | 123 | /** 124 | * This is an array containing information about the address the email came from. 125 | * 126 | * @var string 127 | */ 128 | protected $from; 129 | 130 | /** 131 | * This is an array containing information about the address the email was sent from. 132 | * 133 | * @var string 134 | */ 135 | protected $sender; 136 | 137 | /** 138 | * This is an array of arrays that contains information about the addresses the email was sent to. 139 | * 140 | * @var array 141 | */ 142 | protected $to; 143 | 144 | /** 145 | * This is an array of arrays that contains information about the addresses the email was cc'd to. 146 | * 147 | * @var array 148 | */ 149 | protected $cc; 150 | 151 | /** 152 | * This is an array of arrays that contains information about the addresses the email was bcc'd to. 153 | * 154 | * @var array 155 | */ 156 | protected $bcc; 157 | 158 | /** 159 | * This is an array of arrays that contain information about the addresses that should receive replies to the email. 160 | * 161 | * @var array 162 | */ 163 | protected $replyTo; 164 | 165 | /** 166 | * This is an array of ImapAttachments retrieved from the message. 167 | * 168 | * @var Attachment[] 169 | */ 170 | protected $attachments = array(); 171 | 172 | /** 173 | * Contains the mailbox that the message resides in. 174 | * 175 | * @var string 176 | */ 177 | protected $mailbox; 178 | 179 | /** 180 | * This value defines the encoding we want the email message to use. 181 | * 182 | * @var string 183 | */ 184 | public static $charset = 'UTF-8'; 185 | 186 | /** 187 | * This value defines the flag set for encoding if the mb_convert_encoding 188 | * function can't be found, and in this case iconv encoding will be used. 189 | * 190 | * @var string 191 | */ 192 | public static $charsetFlag = '//TRANSLIT'; 193 | 194 | /** 195 | * These constants can be used to easily access available flags 196 | */ 197 | const FLAG_RECENT = 'recent'; 198 | const FLAG_FLAGGED = 'flagged'; 199 | const FLAG_ANSWERED = 'answered'; 200 | const FLAG_DELETED = 'deleted'; 201 | const FLAG_SEEN = 'seen'; 202 | const FLAG_DRAFT = 'draft'; 203 | 204 | /** 205 | * This constructor takes in the uid for the message and the Imap class representing the mailbox the 206 | * message should be opened from. This constructor should generally not be called directly, but rather retrieved 207 | * through the apprioriate Imap functions. 208 | * 209 | * @param int $messageUniqueId 210 | * @param Server $mailbox 211 | */ 212 | public function __construct($messageUniqueId, Server $connection) 213 | { 214 | $this->imapConnection = $connection; 215 | $this->mailbox = $connection->getMailBox(); 216 | $this->uid = $messageUniqueId; 217 | $this->imapStream = $this->imapConnection->getImapStream(); 218 | if($this->loadMessage() !== true) 219 | throw new \RuntimeException('Message with ID ' . $messageUniqueId . ' not found.'); 220 | } 221 | 222 | /** 223 | * This function is called when the message class is loaded. It loads general information about the message from the 224 | * imap server. 225 | * 226 | */ 227 | protected function loadMessage() 228 | { 229 | 230 | /* First load the message overview information */ 231 | 232 | if(!is_object($messageOverview = $this->getOverview())) 233 | 234 | return false; 235 | 236 | $this->subject = isset($messageOverview->subject) ? imap_utf8($messageOverview->subject) : null; 237 | $this->date = strtotime($messageOverview->date); 238 | $this->size = $messageOverview->size; 239 | 240 | foreach (self::$flagTypes as $flag) 241 | $this->status[$flag] = ($messageOverview->$flag == 1); 242 | 243 | /* Next load in all of the header information */ 244 | 245 | $headers = $this->getHeaders(); 246 | 247 | if (isset($headers->to)) 248 | $this->to = $this->processAddressObject($headers->to); 249 | 250 | if (isset($headers->cc)) 251 | $this->cc = $this->processAddressObject($headers->cc); 252 | 253 | if (isset($headers->bcc)) 254 | $this->bcc = $this->processAddressObject($headers->bcc); 255 | 256 | if (isset($headers->sender)) 257 | $this->sender = $this->processAddressObject($headers->sender); 258 | 259 | $this->from = isset($headers->from) ? $this->processAddressObject($headers->from) : array(''); 260 | $this->replyTo = isset($headers->reply_to) ? $this->processAddressObject($headers->reply_to) : $this->from; 261 | 262 | /* Finally load the structure itself */ 263 | 264 | $structure = $this->getStructure(); 265 | 266 | if (!isset($structure->parts)) { 267 | // not multipart 268 | $this->processStructure($structure); 269 | } else { 270 | // multipart 271 | foreach ($structure->parts as $id => $part) 272 | $this->processStructure($part, $id + 1); 273 | } 274 | 275 | return true; 276 | } 277 | 278 | /** 279 | * This function returns an object containing information about the message. This output is similar to that over the 280 | * imap_fetch_overview function, only instead of an array of message overviews only a single result is returned. The 281 | * results are only retrieved from the server once unless passed true as a parameter. 282 | * 283 | * @param bool $forceReload 284 | * @return \stdClass 285 | */ 286 | public function getOverview($forceReload = false) 287 | { 288 | if ($forceReload || !isset($this->messageOverview)) { 289 | // returns an array, and since we just want one message we can grab the only result 290 | $results = imap_fetch_overview($this->imapStream, $this->uid, FT_UID); 291 | if ( sizeof($results) == 0 ) { 292 | throw new \RuntimeException('Error fetching overview'); 293 | } 294 | $this->messageOverview = array_shift($results); 295 | if ( ! isset($this->messageOverview->date)) { 296 | $this->messageOverview->date = null; 297 | } 298 | } 299 | 300 | return $this->messageOverview; 301 | } 302 | 303 | /** 304 | * This function returns an object containing the raw headers of the message. 305 | * 306 | * @param bool $forceReload 307 | * @return string 308 | */ 309 | public function getRawHeaders($forceReload = false) 310 | { 311 | if ($forceReload || !isset($this->rawHeaders)) { 312 | // raw headers (since imap_headerinfo doesn't use the unique id) 313 | $this->rawHeaders = imap_fetchheader($this->imapStream, $this->uid, FT_UID); 314 | } 315 | 316 | return $this->rawHeaders; 317 | } 318 | 319 | /** 320 | * This function returns an object containing the headers of the message. This is done by taking the raw headers 321 | * and running them through the imap_rfc822_parse_headers function. The results are only retrieved from the server 322 | * once unless passed true as a parameter. 323 | * 324 | * @param bool $forceReload 325 | * @return \stdClass 326 | */ 327 | public function getHeaders($forceReload = false) 328 | { 329 | if ($forceReload || !isset($this->headers)) { 330 | // raw headers (since imap_headerinfo doesn't use the unique id) 331 | $rawHeaders = $this->getRawHeaders(); 332 | 333 | // convert raw header string into a usable object 334 | $headerObject = imap_rfc822_parse_headers($rawHeaders); 335 | 336 | // to keep this object as close as possible to the original header object we add the udate property 337 | if (isset($headerObject->date)) { 338 | $headerObject->udate = strtotime($headerObject->date); 339 | } else { 340 | $headerObject->date = null; 341 | $headerObject->udate = null; 342 | } 343 | 344 | $this->headers = $headerObject; 345 | } 346 | 347 | return $this->headers; 348 | } 349 | 350 | /** 351 | * This function returns an object containing the structure of the message body. This is the same object thats 352 | * returned by imap_fetchstructure. The results are only retrieved from the server once unless passed true as a 353 | * parameter. 354 | * 355 | * @param bool $forceReload 356 | * @return \stdClass 357 | */ 358 | public function getStructure($forceReload = false) 359 | { 360 | if ($forceReload || !isset($this->structure)) { 361 | $this->structure = imap_fetchstructure($this->imapStream, $this->uid, FT_UID); 362 | } 363 | 364 | return $this->structure; 365 | } 366 | 367 | /** 368 | * This function returns the message body of the email. By default it returns the plaintext version. If a plaintext 369 | * version is requested but not present, the html version is stripped of tags and returned. If the opposite occurs, 370 | * the plaintext version is given some html formatting and returned. If neither are present the return value will be 371 | * false. 372 | * 373 | * @param bool $html Pass true to receive an html response. 374 | * @return string|bool Returns false if no body is present. 375 | */ 376 | public function getMessageBody($html = false) 377 | { 378 | if ($html) { 379 | if (!isset($this->htmlMessage) && isset($this->plaintextMessage)) { 380 | $output = nl2br($this->plaintextMessage); 381 | 382 | return $output; 383 | 384 | } elseif (isset($this->htmlMessage)) { 385 | return $this->htmlMessage; 386 | } 387 | } else { 388 | if (!isset($this->plaintextMessage) && isset($this->htmlMessage)) { 389 | $output = preg_replace('/\s*\/i', PHP_EOL, trim($this->htmlMessage) ); 390 | $output = strip_tags($output); 391 | 392 | return $output; 393 | } elseif (isset($this->plaintextMessage)) { 394 | return $this->plaintextMessage; 395 | } 396 | } 397 | 398 | return false; 399 | } 400 | 401 | /** 402 | * This function returns the plain text body of the email or false if not present. 403 | * @return string|bool Returns false if not present 404 | */ 405 | public function getPlainTextBody() 406 | { 407 | return isset($this->plaintextMessage) ? $this->plaintextMessage : false; 408 | } 409 | 410 | /** 411 | * This function returns the HTML body of the email or false if not present. 412 | * @return string|bool Returns false if not present 413 | */ 414 | public function getHtmlBody() 415 | { 416 | return isset($this->htmlMessage) ? $this->htmlMessage : false; 417 | } 418 | 419 | /** 420 | * This function returns either an array of email addresses and names or, optionally, a string that can be used in 421 | * mail headers. 422 | * 423 | * @param string $type Should be 'to', 'cc', 'bcc', 'from', 'sender', or 'reply-to'. 424 | * @param bool $asString 425 | * @return array|string|bool 426 | */ 427 | public function getAddresses($type, $asString = false) 428 | { 429 | $type = ( $type == 'reply-to' ) ? 'replyTo' : $type; 430 | $addressTypes = array('to', 'cc', 'bcc', 'from', 'sender', 'replyTo'); 431 | 432 | if (!in_array($type, $addressTypes) || !isset($this->$type) || count($this->$type) < 1) 433 | return false; 434 | 435 | if (!$asString) { 436 | if ($type == 'from') 437 | return $this->from[0]; 438 | elseif ($type == 'sender') 439 | return $this->sender[0]; 440 | 441 | return $this->$type; 442 | } else { 443 | $outputString = ''; 444 | foreach ($this->$type as $address) { 445 | if (isset($set)) 446 | $outputString .= ', '; 447 | if (!isset($set)) 448 | $set = true; 449 | 450 | $outputString .= isset($address['name']) ? 451 | $address['name'] . ' <' . $address['address'] . '>' 452 | : $address['address']; 453 | } 454 | 455 | return $outputString; 456 | } 457 | } 458 | 459 | /** 460 | * This function returns the date, as a timestamp, of when the email was sent. 461 | * 462 | * @return int 463 | */ 464 | public function getDate() 465 | { 466 | return isset($this->date) ? $this->date : false; 467 | } 468 | 469 | /** 470 | * This returns the subject of the message. 471 | * 472 | * @return string 473 | */ 474 | public function getSubject() 475 | { 476 | return isset($this->subject) ? $this->subject : null; 477 | } 478 | 479 | /** 480 | * This function marks a message for deletion. It is important to note that the message will not be deleted form the 481 | * mailbox until the Imap->expunge it run. 482 | * 483 | * @return bool 484 | */ 485 | public function delete() 486 | { 487 | return imap_delete($this->imapStream, $this->uid, FT_UID); 488 | } 489 | 490 | /** 491 | * This function returns Imap this message came from. 492 | * 493 | * @return Server 494 | */ 495 | public function getImapBox() 496 | { 497 | return $this->imapConnection; 498 | } 499 | 500 | /** 501 | * This function takes in a structure and identifier and processes that part of the message. If that portion of the 502 | * message has its own subparts, those are recursively processed using this function. 503 | * 504 | * @param \stdClass $structure 505 | * @param string $partIdentifier 506 | */ 507 | protected function processStructure($structure, $partIdentifier = null) 508 | { 509 | $parameters = self::getParametersFromStructure($structure); 510 | 511 | if ((isset($parameters['name']) || isset($parameters['filename'])) 512 | || (isset($structure->subtype) && strtolower($structure->subtype) == 'rfc822') 513 | ) { 514 | $attachment = new Attachment($this, $structure, $partIdentifier); 515 | $this->attachments[] = $attachment; 516 | } elseif ($structure->type == 0 || $structure->type == 1) { 517 | $messageBody = isset($partIdentifier) ? 518 | imap_fetchbody($this->imapStream, $this->uid, $partIdentifier, FT_UID ) 519 | : imap_body($this->imapStream, $this->uid, FT_UID ); 520 | 521 | $messageBody = self::decode($messageBody, $structure->encoding); 522 | 523 | if (!empty($parameters['charset']) && $parameters['charset'] !== self::$charset) { 524 | $mb_converted = false; 525 | if (function_exists('mb_convert_encoding')) { 526 | if (!in_array($parameters['charset'], mb_list_encodings())) { 527 | if ($structure->encoding === 0) { 528 | $parameters['charset'] = 'US-ASCII'; 529 | } else { 530 | $parameters['charset'] = 'UTF-8'; 531 | } 532 | } 533 | 534 | $messageBody = @mb_convert_encoding($messageBody, self::$charset, $parameters['charset']); 535 | $mb_converted = true; 536 | } 537 | if (!$mb_converted) { 538 | $messageBodyConv = @iconv($parameters['charset'], self::$charset . self::$charsetFlag, $messageBody); 539 | 540 | if ($messageBodyConv !== false) { 541 | $messageBody = $messageBodyConv; 542 | } 543 | } 544 | } 545 | 546 | if (strtolower($structure->subtype) === 'plain' || ($structure->type == 1 && strtolower($structure->subtype) !== 'alternative')) { 547 | if (isset($this->plaintextMessage)) { 548 | $this->plaintextMessage .= PHP_EOL . PHP_EOL; 549 | } else { 550 | $this->plaintextMessage = ''; 551 | } 552 | 553 | $this->plaintextMessage .= trim($messageBody); 554 | } elseif (strtolower($structure->subtype) === 'html') { 555 | if (isset($this->htmlMessage)) { 556 | $this->htmlMessage .= '

'; 557 | } else { 558 | $this->htmlMessage = ''; 559 | } 560 | 561 | $this->htmlMessage .= $messageBody; 562 | } 563 | } 564 | 565 | if (isset($structure->parts)) { // multipart: iterate through each part 566 | 567 | foreach ($structure->parts as $partIndex => $part) { 568 | $partId = $partIndex + 1; 569 | 570 | if (isset($partIdentifier)) 571 | $partId = $partIdentifier . '.' . $partId; 572 | 573 | $this->processStructure($part, $partId); 574 | } 575 | } 576 | } 577 | 578 | /** 579 | * This function takes in the message data and encoding type and returns the decoded data. 580 | * 581 | * @param string $data 582 | * @param int|string $encoding 583 | * @return string 584 | */ 585 | public static function decode($data, $encoding) 586 | { 587 | if (!is_numeric($encoding)) { 588 | $encoding = strtolower($encoding); 589 | } 590 | 591 | switch (true) { 592 | case $encoding === 'quoted-printable': 593 | case $encoding === 4: 594 | return quoted_printable_decode($data); 595 | 596 | case $encoding === 'base64': 597 | case $encoding === 3: 598 | return base64_decode($data); 599 | 600 | default: 601 | return $data; 602 | } 603 | } 604 | 605 | /** 606 | * This function returns the body type that an imap integer maps to. 607 | * 608 | * @param int $id 609 | * @return string 610 | */ 611 | public static function typeIdToString($id) 612 | { 613 | switch ($id) { 614 | case 0: 615 | return 'text'; 616 | 617 | case 1: 618 | return 'multipart'; 619 | 620 | case 2: 621 | return 'message'; 622 | 623 | case 3: 624 | return 'application'; 625 | 626 | case 4: 627 | return 'audio'; 628 | 629 | case 5: 630 | return 'image'; 631 | 632 | case 6: 633 | return 'video'; 634 | 635 | default: 636 | case 7: 637 | return 'other'; 638 | } 639 | } 640 | 641 | /** 642 | * Takes in a section structure and returns its parameters as an associative array. 643 | * 644 | * @param \stdClass $structure 645 | * @return array 646 | */ 647 | public static function getParametersFromStructure($structure) 648 | { 649 | $parameters = array(); 650 | if (isset($structure->parameters)) 651 | foreach ($structure->parameters as $parameter) 652 | $parameters[strtolower($parameter->attribute)] = $parameter->value; 653 | 654 | if (isset($structure->dparameters)) 655 | foreach ($structure->dparameters as $parameter) 656 | $parameters[strtolower($parameter->attribute)] = $parameter->value; 657 | 658 | return $parameters; 659 | } 660 | 661 | /** 662 | * This function takes in an array of the address objects generated by the message headers and turns them into an 663 | * associative array. 664 | * 665 | * @param array $addresses 666 | * @return array 667 | */ 668 | protected function processAddressObject($addresses) 669 | { 670 | $outputAddresses = array(); 671 | if (is_array($addresses)) 672 | foreach ($addresses as $address) { 673 | if (property_exists($address, 'mailbox') && $address->mailbox != 'undisclosed-recipients') { 674 | $currentAddress = array(); 675 | $currentAddress['address'] = $address->mailbox . '@' . $address->host; 676 | if (isset($address->personal)) { 677 | $currentAddress['name'] = $address->personal; 678 | } 679 | $outputAddresses[] = $currentAddress; 680 | } 681 | } 682 | 683 | return $outputAddresses; 684 | } 685 | 686 | /** 687 | * This function returns the unique id that identifies the message on the server. 688 | * 689 | * @return int 690 | */ 691 | public function getUid() 692 | { 693 | return $this->uid; 694 | } 695 | 696 | /** 697 | * This function returns the attachments a message contains. If a filename is passed then just that ImapAttachment 698 | * is returned, unless 699 | * 700 | * @param null|string $filename 701 | * @return array|bool|Attachment[] 702 | */ 703 | public function getAttachments($filename = null) 704 | { 705 | if (!isset($this->attachments) || count($this->attachments) < 1) 706 | return false; 707 | 708 | if (!isset($filename)) 709 | return $this->attachments; 710 | 711 | $results = array(); 712 | foreach ($this->attachments as $attachment) { 713 | if ($attachment->getFileName() == $filename) 714 | $results[] = $attachment; 715 | } 716 | 717 | switch (count($results)) { 718 | case 0: 719 | return false; 720 | 721 | case 1: 722 | return array_shift($results); 723 | 724 | default: 725 | return $results; 726 | break; 727 | } 728 | } 729 | 730 | /** 731 | * This function checks to see if an imap flag is set on the email message. 732 | * 733 | * @param string $flag Recent, Flagged, Answered, Deleted, Seen, Draft 734 | * @return bool 735 | */ 736 | public function checkFlag($flag = self::FLAG_FLAGGED) 737 | { 738 | return (isset($this->status[$flag]) && $this->status[$flag] === true); 739 | } 740 | 741 | /** 742 | * This function is used to enable or disable one or more flags on the imap message. 743 | * 744 | * @param string|array $flag Flagged, Answered, Deleted, Seen, Draft 745 | * @param bool $enable 746 | * @throws \InvalidArgumentException 747 | * @return bool 748 | */ 749 | public function setFlag($flag, $enable = true) 750 | { 751 | $flags = (is_array($flag)) ? $flag : array($flag); 752 | 753 | foreach ($flags as $i => $flag) { 754 | $flag = ltrim(strtolower($flag), '\\'); 755 | if (!in_array($flag, self::$flagTypes) || $flag == self::FLAG_RECENT) 756 | throw new \InvalidArgumentException('Unable to set invalid flag "' . $flag . '"'); 757 | 758 | if ($enable) { 759 | $this->status[$flag] = true; 760 | } else { 761 | unset($this->status[$flag]); 762 | } 763 | 764 | $flags[$i] = $flag; 765 | } 766 | 767 | $imapifiedFlag = '\\'.implode(' \\', array_map('ucfirst', $flags)); 768 | 769 | if ($enable === true) { 770 | return imap_setflag_full($this->imapStream, $this->uid, $imapifiedFlag, ST_UID); 771 | } else { 772 | return imap_clearflag_full($this->imapStream, $this->uid, $imapifiedFlag, ST_UID); 773 | } 774 | } 775 | 776 | /** 777 | * This function is used to move a mail to the given mailbox. 778 | * 779 | * @param $mailbox 780 | * 781 | * @return bool 782 | */ 783 | public function moveToMailBox($mailbox) 784 | { 785 | $currentBox = $this->imapConnection->getMailBox(); 786 | $this->imapConnection->setMailBox($this->mailbox); 787 | 788 | $returnValue = imap_mail_copy($this->imapStream, $this->uid, $mailbox, CP_UID | CP_MOVE); 789 | imap_expunge($this->imapStream); 790 | 791 | $this->mailbox = $mailbox; 792 | 793 | $this->imapConnection->setMailBox($currentBox); 794 | 795 | return $returnValue; 796 | } 797 | } 798 | -------------------------------------------------------------------------------- /vendor/tedivm/fetch/src/Fetch/Server.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Fetch; 13 | 14 | /** 15 | * This library is a wrapper around the Imap library functions included in php. This class in particular manages a 16 | * connection to the server (imap, pop, etc) and allows for the easy retrieval of stored messages. 17 | * 18 | * @package Fetch 19 | * @author Robert Hafner 20 | */ 21 | class Server 22 | { 23 | /** 24 | * When SSL isn't compiled into PHP we need to make some adjustments to prevent soul crushing annoyances. 25 | * 26 | * @var bool 27 | */ 28 | public static $sslEnable = true; 29 | 30 | /** 31 | * These are the flags that depend on ssl support being compiled into imap. 32 | * 33 | * @var array 34 | */ 35 | public static $sslFlags = array('ssl', 'validate-cert', 'novalidate-cert', 'tls', 'notls'); 36 | 37 | /** 38 | * This is used to prevent the class from putting up conflicting tags. Both directions- key to value, value to key- 39 | * are checked, so if "novalidate-cert" is passed then "validate-cert" is removed, and vice-versa. 40 | * 41 | * @var array 42 | */ 43 | public static $exclusiveFlags = array('validate-cert' => 'novalidate-cert', 'tls' => 'notls'); 44 | 45 | /** 46 | * This is the domain or server path the class is connecting to. 47 | * 48 | * @var string 49 | */ 50 | protected $serverPath; 51 | 52 | /** 53 | * This is the name of the current mailbox the connection is using. 54 | * 55 | * @var string 56 | */ 57 | protected $mailbox = ''; 58 | 59 | /** 60 | * This is the username used to connect to the server. 61 | * 62 | * @var string 63 | */ 64 | protected $username; 65 | 66 | /** 67 | * This is the password used to connect to the server. 68 | * 69 | * @var string 70 | */ 71 | protected $password; 72 | 73 | /** 74 | * This is an array of flags that modify how the class connects to the server. Examples include "ssl" to enforce a 75 | * secure connection or "novalidate-cert" to allow for self-signed certificates. 76 | * 77 | * @link http://us.php.net/manual/en/function.imap-open.php 78 | * @var array 79 | */ 80 | protected $flags = array(); 81 | 82 | /** 83 | * This is the port used to connect to the server 84 | * 85 | * @var int 86 | */ 87 | protected $port; 88 | 89 | /** 90 | * This is the set of options, represented by a bitmask, to be passed to the server during connection. 91 | * 92 | * @var int 93 | */ 94 | protected $options = 0; 95 | 96 | /** 97 | * This is the set of connection parameters 98 | * 99 | * @var array 100 | */ 101 | protected $params = array(); 102 | 103 | /** 104 | * This is the resource connection to the server. It is required by a number of imap based functions to specify how 105 | * to connect. 106 | * 107 | * @var resource 108 | */ 109 | protected $imapStream; 110 | 111 | /** 112 | * This is the name of the service currently being used. Imap is the default, although pop3 and nntp are also 113 | * options 114 | * 115 | * @var string 116 | */ 117 | protected $service = 'imap'; 118 | 119 | /** 120 | * This constructor takes the location and service thats trying to be connected to as its arguments. 121 | * 122 | * @param string $serverPath 123 | * @param null|int $port 124 | * @param null|string $service 125 | */ 126 | public function __construct($serverPath, $port = 143, $service = 'imap') 127 | { 128 | $this->serverPath = $serverPath; 129 | 130 | $this->port = $port; 131 | 132 | switch ($port) { 133 | case 143: 134 | $this->setFlag('novalidate-cert'); 135 | break; 136 | 137 | case 993: 138 | $this->setFlag('ssl'); 139 | break; 140 | } 141 | 142 | $this->service = $service; 143 | } 144 | 145 | /** 146 | * This function sets the username and password used to connect to the server. 147 | * 148 | * @param string $username 149 | * @param string $password 150 | * @param bool $tryFasterAuth tries to auth faster by disabling GSSAPI & NTLM auth methods (set to false if you use either of these auth methods) 151 | */ 152 | public function setAuthentication($username, $password, $tryFasterAuth=true) 153 | { 154 | $this->username = $username; 155 | $this->password = $password; 156 | if ($tryFasterAuth) { 157 | $this->setParam('DISABLE_AUTHENTICATOR', array('GSSAPI','NTLM')); 158 | } 159 | } 160 | 161 | /** 162 | * This function sets the mailbox to connect to. 163 | * 164 | * @param string $mailbox 165 | * @return bool 166 | */ 167 | public function setMailBox($mailbox = '') 168 | { 169 | if (!$this->hasMailBox($mailbox)) { 170 | return false; 171 | } 172 | 173 | $this->mailbox = $mailbox; 174 | if (isset($this->imapStream)) { 175 | $this->setImapStream(); 176 | } 177 | 178 | return true; 179 | } 180 | 181 | public function getMailBox() 182 | { 183 | return $this->mailbox; 184 | } 185 | 186 | /** 187 | * This function sets or removes flag specifying connection behavior. In many cases the flag is just a one word 188 | * deal, so the value attribute is not required. However, if the value parameter is passed false it will clear that 189 | * flag. 190 | * 191 | * @param string $flag 192 | * @param null|string|bool $value 193 | */ 194 | public function setFlag($flag, $value = null) 195 | { 196 | if (!self::$sslEnable && in_array($flag, self::$sslFlags)) 197 | return; 198 | 199 | if (isset(self::$exclusiveFlags[$flag])) { 200 | $kill = self::$exclusiveFlags[$flag]; 201 | } elseif ($index = array_search($flag, self::$exclusiveFlags)) { 202 | $kill = $index; 203 | } 204 | 205 | if (isset($kill) && false !== $index = array_search($kill, $this->flags)) 206 | unset($this->flags[$index]); 207 | 208 | $index = array_search($flag, $this->flags); 209 | if (isset($value) && $value !== true) { 210 | if ($value == false && $index !== false) { 211 | unset($this->flags[$index]); 212 | } elseif ($value != false) { 213 | $match = preg_grep('/' . $flag . '/', $this->flags); 214 | if (reset($match)) { 215 | $this->flags[key($match)] = $flag . '=' . $value; 216 | } else { 217 | $this->flags[] = $flag . '=' . $value; 218 | } 219 | } 220 | } elseif ($index === false) { 221 | $this->flags[] = $flag; 222 | } 223 | } 224 | 225 | /** 226 | * This funtion is used to set various options for connecting to the server. 227 | * 228 | * @param int $bitmask 229 | * @throws \Exception 230 | */ 231 | public function setOptions($bitmask = 0) 232 | { 233 | if (!is_numeric($bitmask)) 234 | throw new \RuntimeException('Function requires numeric argument.'); 235 | 236 | $this->options = $bitmask; 237 | } 238 | 239 | /** 240 | * This function is used to set connection parameters 241 | * 242 | * @param string $key 243 | * @param string $value 244 | */ 245 | public function setParam($key, $value) 246 | { 247 | $this->params[$key] = $value; 248 | } 249 | 250 | /** 251 | * This function gets the current saved imap resource and returns it. 252 | * 253 | * @return resource 254 | */ 255 | public function getImapStream() 256 | { 257 | if (empty($this->imapStream)) 258 | $this->setImapStream(); 259 | 260 | return $this->imapStream; 261 | } 262 | 263 | /** 264 | * This function takes in all of the connection date (server, port, service, flags, mailbox) and creates the string 265 | * thats passed to the imap_open function. 266 | * 267 | * @return string 268 | */ 269 | public function getServerString() 270 | { 271 | $mailboxPath = $this->getServerSpecification(); 272 | 273 | if (isset($this->mailbox)) 274 | $mailboxPath .= $this->mailbox; 275 | 276 | return $mailboxPath; 277 | } 278 | 279 | /** 280 | * Returns the server specification, without adding any mailbox. 281 | * 282 | * @return string 283 | */ 284 | protected function getServerSpecification() 285 | { 286 | $mailboxPath = '{' . $this->serverPath; 287 | 288 | if (isset($this->port)) 289 | $mailboxPath .= ':' . $this->port; 290 | 291 | if ($this->service != 'imap') 292 | $mailboxPath .= '/' . $this->service; 293 | 294 | foreach ($this->flags as $flag) { 295 | $mailboxPath .= '/' . $flag; 296 | } 297 | 298 | $mailboxPath .= '}'; 299 | 300 | return $mailboxPath; 301 | } 302 | 303 | /** 304 | * This function creates or reopens an imapStream when called. 305 | * 306 | */ 307 | protected function setImapStream() 308 | { 309 | if (!empty($this->imapStream)) { 310 | if (!imap_reopen($this->imapStream, $this->getServerString(), $this->options, 1)) 311 | throw new \RuntimeException(imap_last_error()); 312 | } else { 313 | $imapStream = @imap_open($this->getServerString(), $this->username, $this->password, $this->options, 1, $this->params); 314 | 315 | if ($imapStream === false) 316 | throw new \RuntimeException(imap_last_error()); 317 | 318 | $this->imapStream = $imapStream; 319 | } 320 | } 321 | 322 | /** 323 | * This returns the number of messages that the current mailbox contains. 324 | * 325 | * @param string $mailbox 326 | * @return int 327 | */ 328 | public function numMessages($mailbox='') 329 | { 330 | $cnt = 0; 331 | if ($mailbox==='') { 332 | $cnt = imap_num_msg($this->getImapStream()); 333 | } elseif ($this->hasMailbox($mailbox) && $mailbox !== '') { 334 | $oldMailbox = $this->getMailBox(); 335 | $this->setMailbox($mailbox); 336 | $cnt = $this->numMessages(); 337 | $this->setMailbox($oldMailbox); 338 | } 339 | 340 | return ((int) $cnt); 341 | } 342 | 343 | /** 344 | * This function returns an array of ImapMessage object for emails that fit the criteria passed. The criteria string 345 | * should be formatted according to the imap search standard, which can be found on the php "imap_search" page or in 346 | * section 6.4.4 of RFC 2060 347 | * 348 | * @link http://us.php.net/imap_search 349 | * @link http://www.faqs.org/rfcs/rfc2060 350 | * @param string $criteria 351 | * @param null|int $limit 352 | * @return array An array of ImapMessage objects 353 | */ 354 | public function search($criteria = 'ALL', $limit = null) 355 | { 356 | if ($results = imap_search($this->getImapStream(), $criteria, SE_UID)) { 357 | if (isset($limit) && count($results) > $limit) 358 | $results = array_slice($results, 0, $limit); 359 | 360 | $messages = array(); 361 | 362 | foreach ($results as $messageId) 363 | $messages[] = new Message($messageId, $this); 364 | 365 | return $messages; 366 | } else { 367 | return array(); 368 | } 369 | } 370 | 371 | /** 372 | * This function returns the recently received emails as an array of ImapMessage objects. 373 | * 374 | * @param null|int $limit 375 | * @return array An array of ImapMessage objects for emails that were recently received by the server. 376 | */ 377 | public function getRecentMessages($limit = null) 378 | { 379 | return $this->search('Recent', $limit); 380 | } 381 | 382 | /** 383 | * Returns the emails in the current mailbox as an array of ImapMessage objects. 384 | * 385 | * @param null|int $limit 386 | * @return Message[] 387 | */ 388 | public function getMessages($limit = null) 389 | { 390 | $numMessages = $this->numMessages(); 391 | 392 | if (isset($limit) && is_numeric($limit) && $limit < $numMessages) 393 | $numMessages = $limit; 394 | 395 | if ($numMessages < 1) 396 | return array(); 397 | 398 | $stream = $this->getImapStream(); 399 | $messages = array(); 400 | for ($i = 1; $i <= $numMessages; $i++) { 401 | $uid = imap_uid($stream, $i); 402 | $messages[] = new Message($uid, $this); 403 | } 404 | 405 | return $messages; 406 | } 407 | 408 | /** 409 | * Returns the emails in the current mailbox as an array of ImapMessage objects 410 | * ordered by some ordering 411 | * 412 | * @see http://php.net/manual/en/function.imap-sort.php 413 | * @param int $orderBy 414 | * @param bool $reverse 415 | * @param int $limit 416 | * @return Message[] 417 | */ 418 | public function getOrderedMessages($orderBy, $reverse, $limit) 419 | { 420 | $msgIds = imap_sort($this->getImapStream(), $orderBy, $reverse ? 1 : 0, SE_UID); 421 | 422 | return array_map(array($this, 'getMessageByUid'), array_slice($msgIds, 0, $limit)); 423 | } 424 | 425 | /** 426 | * Returns the requested email or false if it is not found. 427 | * 428 | * @param int $uid 429 | * @return Message|bool 430 | */ 431 | public function getMessageByUid($uid) 432 | { 433 | try { 434 | $message = new \Fetch\Message($uid, $this); 435 | 436 | return $message; 437 | } catch (\Exception $e) { 438 | return false; 439 | } 440 | } 441 | 442 | /** 443 | * This function removes all of the messages flagged for deletion from the mailbox. 444 | * 445 | * @return bool 446 | */ 447 | public function expunge() 448 | { 449 | return imap_expunge($this->getImapStream()); 450 | } 451 | 452 | /** 453 | * Checks if the given mailbox exists. 454 | * 455 | * @param $mailbox 456 | * 457 | * @return bool 458 | */ 459 | public function hasMailBox($mailbox) 460 | { 461 | return (boolean) $this->getMailBoxDetails($mailbox); 462 | } 463 | 464 | /** 465 | * Return information about the mailbox or mailboxes 466 | * 467 | * @param $mailbox 468 | * 469 | * @return array 470 | */ 471 | public function getMailBoxDetails($mailbox) 472 | { 473 | return imap_getmailboxes( 474 | $this->getImapStream(), 475 | $this->getServerString(), 476 | $this->getServerSpecification() . $mailbox 477 | ); 478 | } 479 | 480 | /** 481 | * Creates the given mailbox. 482 | * 483 | * @param $mailbox 484 | * 485 | * @return bool 486 | */ 487 | public function createMailBox($mailbox) 488 | { 489 | return imap_createmailbox($this->getImapStream(), $this->getServerSpecification() . $mailbox); 490 | } 491 | 492 | /** 493 | * List available mailboxes 494 | * 495 | * @param string $pattern 496 | * 497 | * @return array 498 | */ 499 | public function listMailBoxes($pattern = '*') 500 | { 501 | return imap_list($this->getImapStream(), $this->getServerSpecification(), $pattern); 502 | } 503 | 504 | /** 505 | * Deletes the given mailbox. 506 | * 507 | * @param $mailbox 508 | * 509 | * @return bool 510 | */ 511 | public function deleteMailBox($mailbox) 512 | { 513 | return imap_deletemailbox($this->getImapStream(), $this->getServerSpecification() . $mailbox); 514 | } 515 | } 516 | -------------------------------------------------------------------------------- /vendor/tedivm/fetch/tests/Fetch/Test/AttachmentTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Fetch\Test; 13 | 14 | /** 15 | * @package Fetch 16 | * @author Robert Hafner 17 | */ 18 | class AttachmentTest extends \PHPUnit_Framework_TestCase 19 | { 20 | 21 | public static function getAttachments($MessageId) 22 | { 23 | $server = ServerTest::getServer(); 24 | $message = new \Fetch\Message($MessageId, $server); 25 | $attachments = $message->getAttachments(); 26 | $returnAttachments = array(); 27 | foreach($attachments as $attachment) 28 | $returnAttachments[$attachment->getFileName()] = $attachment; 29 | 30 | return $returnAttachments; 31 | } 32 | 33 | public function testGetData() 34 | { 35 | $attachments = static::getAttachments('6'); 36 | 37 | $attachment_RCA = $attachments['RCA_Indian_Head_test_pattern.JPG.zip']; 38 | $md5_RCA = '3e9b6f02551590a7bcfff5d50b5b7b20'; 39 | $this->assertEquals($md5_RCA, md5($attachment_RCA->getData())); 40 | 41 | $attachment_TestCard = $attachments['Test_card.png.zip']; 42 | $md5_TestCard = '94c40bd83fbfa03b29bf1811f9aaccea'; 43 | $this->assertEquals($md5_TestCard, md5($attachment_TestCard->getData())); 44 | } 45 | 46 | public function testGetMimeType() 47 | { 48 | $attachments = static::getAttachments('6'); 49 | 50 | $attachment_RCA = $attachments['RCA_Indian_Head_test_pattern.JPG.zip']; 51 | $mimetype_RCA = 'application/zip'; 52 | $this->assertEquals($mimetype_RCA, $attachment_RCA->getMimeType()); 53 | 54 | $attachment_TestCard = $attachments['Test_card.png.zip']; 55 | $mimetype_TestCard = 'application/zip'; 56 | $this->assertEquals($mimetype_TestCard, $attachment_TestCard->getMimeType()); 57 | } 58 | 59 | public function testGetSize() 60 | { 61 | $attachments = static::getAttachments('6'); 62 | 63 | $attachment_RCA = $attachments['RCA_Indian_Head_test_pattern.JPG.zip']; 64 | $size_RCA = 378338; 65 | $this->assertEquals($size_RCA, $attachment_RCA->getSize()); 66 | 67 | $attachment_TestCard = $attachments['Test_card.png.zip']; 68 | $size_TestCard = 32510; 69 | $this->assertEquals($size_TestCard, $attachment_TestCard->getSize()); 70 | } 71 | 72 | public function testGetStructure() 73 | { 74 | $attachments = static::getAttachments('6'); 75 | 76 | $attachment_RCA = $attachments['RCA_Indian_Head_test_pattern.JPG.zip']; 77 | $structure_RCA = $attachment_RCA->getStructure(); 78 | 79 | $this->assertObjectHasAttribute('type', $structure_RCA); 80 | $this->assertEquals(3, $structure_RCA->type); 81 | 82 | $this->assertObjectHasAttribute('subtype', $structure_RCA); 83 | $this->assertEquals('ZIP', $structure_RCA->subtype); 84 | 85 | $this->assertObjectHasAttribute('bytes', $structure_RCA); 86 | $this->assertEquals(378338, $structure_RCA->bytes); 87 | } 88 | 89 | public function testSaveToDirectory() 90 | { 91 | $attachments = static::getAttachments('6'); 92 | 93 | $attachment_RCA = $attachments['RCA_Indian_Head_test_pattern.JPG.zip']; 94 | 95 | $tmpdir = rtrim(sys_get_temp_dir(), '/') . '/'; 96 | $filepath = $tmpdir . 'RCA_Indian_Head_test_pattern.JPG.zip'; 97 | 98 | $this->assertTrue($attachment_RCA->saveToDirectory($tmpdir)); 99 | 100 | $this->assertFileExists($filepath); 101 | $this->assertEquals(md5(file_get_contents($filepath)), md5($attachment_RCA->getData())); 102 | 103 | $attachments = static::getAttachments('6'); 104 | $attachment_RCA = $attachments['RCA_Indian_Head_test_pattern.JPG.zip']; 105 | $this->assertFalse($attachment_RCA->saveToDirectory('/'), 'Returns false when attempting to save without filesystem permission.'); 106 | 107 | $attachments = static::getAttachments('6'); 108 | $attachment_RCA = $attachments['RCA_Indian_Head_test_pattern.JPG.zip']; 109 | $this->assertFalse($attachment_RCA->saveToDirectory($filepath), 'Returns false when attempting to save over a file.'); 110 | } 111 | 112 | public static function tearDownAfterClass() 113 | { 114 | $tmpdir = rtrim(sys_get_temp_dir(), '/') . '/'; 115 | $filepath = $tmpdir . 'RCA_Indian_Head_test_pattern.JPG.zip'; 116 | unlink($filepath); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /vendor/tedivm/fetch/tests/Fetch/Test/MessageTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Fetch\Test; 13 | use Fetch\Message; 14 | 15 | /** 16 | * @package Fetch 17 | * @author Robert Hafner 18 | */ 19 | class MessageTest extends \PHPUnit_Framework_TestCase 20 | { 21 | public static function getMessage($id) 22 | { 23 | $server = ServerTest::getServer(); 24 | 25 | return new \Fetch\Message($id, $server); 26 | } 27 | 28 | public function testConstructMessage() 29 | { 30 | $message = static::getMessage(3); 31 | $this->assertInstanceOf('\Fetch\Message', $message); 32 | } 33 | 34 | public function testGetOverview() 35 | { 36 | $message = static::getMessage(3); 37 | $overview = $message->getOverview(); 38 | $this->assertEquals('Welcome', $overview->subject, 'Subject available from overview'); 39 | $this->assertEquals('tedivm@tedivm.com', $overview->from, 'From available from overview'); 40 | $this->assertEquals('testuser@tedivm.com', $overview->to, 'To available from overview'); 41 | $this->assertEquals(1465, $overview->size, 'Size available from overview'); 42 | $this->assertEquals(0, $overview->flagged, 'Flagged available from overview'); 43 | $this->assertEquals(1, $overview->seen, 'Seen available from overview'); 44 | } 45 | 46 | public function testGetHeaders() 47 | { 48 | $message = static::getMessage(3); 49 | $headers = $message->getHeaders(); 50 | $this->assertEquals('Sun, 1 Dec 2013 21:14:03 -0800 (PST)', $headers->date, 'Headers contain the right date.'); 51 | $this->assertEquals('testuser@tedivm.com', $headers->toaddress, 'Headers contain toaddress.'); 52 | $this->assertEquals('tedivm@tedivm.com', $headers->fromaddress, 'Headers contain fromaddress'); 53 | } 54 | 55 | public function testGetStructure() 56 | { 57 | 58 | } 59 | 60 | public function testGetMessageBody() 61 | { 62 | // easiest way to deal with php encoding issues is simply not to. 63 | $plaintextTest = 'f9377a89c9c935463a2b35c92dd61042'; 64 | $convertedHtmlTest = '11498bcf191900d634ff8772a64ca523'; 65 | $pureHtmlTest = '6a366ddecf080199284146d991d52169'; 66 | 67 | $message = static::getMessage(3); 68 | $messageNonHTML = $message->getMessageBody(); 69 | $this->assertEquals($plaintextTest, md5($messageNonHTML), 'Message returns as plaintext.'); 70 | 71 | $messageHTML = $message->getMessageBody(true); 72 | $this->assertEquals($convertedHtmlTest, md5($messageHTML), 'Message converts from plaintext to HTML when requested.'); 73 | 74 | $message = static::getMessage(4); 75 | $messageHTML = $message->getMessageBody(true); 76 | $this->assertEquals($pureHtmlTest, md5($messageHTML), 'Message returns as HTML.'); 77 | 78 | } 79 | 80 | public function testGetPlainTextBody() 81 | { 82 | // easiest way to deal with php encoding issues is simply not to. 83 | $plaintextTest1 = 'f9377a89c9c935463a2b35c92dd61042'; 84 | $plaintextTest2 = '0b8fc9b534a1789f1071f996f238a07a'; 85 | $plaintextTest3 = 'd41d8cd98f00b204e9800998ecf8427e'; 86 | 87 | $message = static::getMessage(3); 88 | $messagePlainText = $message->getPlainTextBody(); 89 | $this->assertEquals($plaintextTest1, md5($messagePlainText), 'Message returns as plaintext.'); 90 | 91 | $message = static::getMessage(4); 92 | $messagePlainText = $message->getPlainTextBody(); 93 | $this->assertEquals($plaintextTest2, md5($messagePlainText), 'Message returns as plaintext.'); 94 | 95 | $message = static::getMessage(6); 96 | $messagePlainText = $message->getPlainTextBody(); 97 | $this->assertEquals($plaintextTest3, md5($messagePlainText), 'Message does not return as plaintext.'); 98 | 99 | } 100 | 101 | public function testGetHtmlBody() 102 | { 103 | // easiest way to deal with php encoding issues is simply not to. 104 | $HtmlTest1 = 'd41d8cd98f00b204e9800998ecf8427e'; 105 | $HtmlTest2 = '6a366ddecf080199284146d991d52169'; 106 | 107 | $message = static::getMessage(3); 108 | $messageHtml = $message->getHtmlBody(); 109 | $this->assertEquals($HtmlTest1, md5($messageHtml), 'Message does not return as HTML.'); 110 | 111 | $message = static::getMessage(4); 112 | $messageHtml = $message->getHtmlBody(); 113 | $this->assertEquals($HtmlTest2, md5($messageHtml), 'Message returns as HTML.'); 114 | 115 | } 116 | 117 | public function testGetAddresses() 118 | { 119 | $message = static::getMessage(3); 120 | 121 | $addresses = $message->getAddresses('to'); 122 | $this->assertEquals('testuser@tedivm.com', $addresses[0]['address'], 'Retrieving to user from address array.'); 123 | 124 | $addressString = $message->getAddresses('to', true); 125 | $this->assertEquals('testuser@tedivm.com', $addressString, 'Returning To address as string.'); 126 | 127 | $addresses = $message->getAddresses('from'); 128 | $this->assertEquals('tedivm@tedivm.com', $addresses['address'], 'Returning From address as an address array.'); 129 | 130 | $addressString = $message->getAddresses('from', true); 131 | $this->assertEquals('tedivm@tedivm.com', $addressString, 'Returning From address as string.'); 132 | } 133 | 134 | public function testGetDate() 135 | { 136 | $message = static::getMessage(3); 137 | $this->assertEquals(1385961243, $message->getDate(), 'Returns date as timestamp.'); 138 | } 139 | 140 | public function testGetSubject() 141 | { 142 | $message = static::getMessage(3); 143 | $this->assertEquals('Welcome', $message->getSubject(), 'Returns Subject.'); 144 | } 145 | 146 | public function testDelete() 147 | { 148 | 149 | } 150 | 151 | public function testGetImapBox() 152 | { 153 | $server = ServerTest::getServer(); 154 | $message = new \Fetch\Message('3', $server); 155 | $this->assertEquals($server, $message->getImapBox(), 'getImapBox returns Server used to create Message.'); 156 | } 157 | 158 | public function testGetUid() 159 | { 160 | $message = static::getMessage('3'); 161 | $this->assertEquals(3, $message->getUid(), 'Message returns UID'); 162 | } 163 | 164 | public function testGetAttachments() 165 | { 166 | $messageWithoutAttachments = static::getMessage('3'); 167 | $this->assertFalse($messageWithoutAttachments->getAttachments(), 'getAttachments returns false when no attachments present.'); 168 | 169 | $messageWithAttachments = static::getMessage('6'); 170 | $attachments = $messageWithAttachments->getAttachments(); 171 | $this->assertCount(2, $attachments); 172 | foreach($attachments as $attachment) 173 | $this->assertInstanceOf('\Fetch\Attachment', $attachment, 'getAttachments returns Fetch\Attachment objects.'); 174 | 175 | $attachment = $messageWithAttachments->getAttachments('Test_card.png.zip'); 176 | $this->assertInstanceOf('\Fetch\Attachment', $attachment, 'getAttachment returns specified Fetch\Attachment object.'); 177 | } 178 | 179 | public function testCheckFlag() 180 | { 181 | $message = static::getMessage('3'); 182 | $this->assertFalse($message->checkFlag('flagged')); 183 | $this->assertTrue($message->checkFlag('seen')); 184 | } 185 | 186 | public function testSetFlag() 187 | { 188 | $message = static::getMessage('3'); 189 | $this->assertFalse($message->checkFlag('answered'), 'Message is not answered.'); 190 | 191 | $this->assertTrue($message->setFlag('answered'), 'setFlag returned true.'); 192 | $this->assertTrue($message->checkFlag('answered'), 'Message was successfully answered.'); 193 | 194 | $this->assertTrue($message->setFlag('answered', false), 'setFlag returned true.'); 195 | $this->assertFalse($message->checkFlag('answered'), 'Message was successfully unanswered.'); 196 | 197 | $message = static::getMessage('2'); 198 | $this->assertFalse($message->checkFlag('flagged'), 'Message is not flagged.'); 199 | 200 | $this->assertTrue($message->setFlag('flagged'), 'setFlag returned true.'); 201 | $this->assertTrue($message->checkFlag('flagged'), 'Message was successfully flagged.'); 202 | 203 | $message = static::getMessage('2'); 204 | $this->assertTrue($message->setFlag('flagged', false), 'setFlag returned true.'); 205 | $this->assertFalse($message->checkFlag('flagged'), 'Message was successfully unflagged.'); 206 | } 207 | 208 | public function testMoveToMailbox() 209 | { 210 | $server = ServerTest::getServer(); 211 | 212 | // Testing by moving message from "Test Folder" to "Sent" 213 | 214 | // Count Test Folder 215 | $testFolderNumStart = $server->numMessages('Test Folder'); 216 | $server->setMailbox('Test Folder'); 217 | $this->assertEquals($testFolderNumStart, $server->numMessages(), 'Server presents consistent information between numMessages when mailbox set and directly queried for number of messages'); 218 | 219 | // Get message from Test Folder 220 | $message = current($server->getMessages(1)); 221 | $this->assertInstanceOf('\Fetch\Message', $message, 'Server returned Message.'); 222 | 223 | // Switch to Sent folder, count messages 224 | $sentFolderNumStart = $server->numMessages('Sent'); 225 | $server->setMailbox('Sent'); 226 | $this->assertEquals($sentFolderNumStart, $server->numMessages(), 'Server presents consistent information between numMessages when mailbox set and directly queried for number of messages'); 227 | 228 | // Switch to "Flagged" folder in order to test that function properly returns to it 229 | $this->assertTrue($server->setMailBox('Flagged Email')); 230 | // Move the message! 231 | $this->assertTrue($message->moveToMailBox('Sent')); 232 | // Make sure we're still in the same folder 233 | $this->assertEquals('Flagged Email', $server->getMailBox(), 'Returned Server back to right mailbox.'); 234 | $this->assertAttributeEquals('Sent', 'mailbox', $message, 'Message mailbox changed to new location.'); 235 | // Make sure Test Folder lost a message 236 | $this->assertTrue($server->setMailBox('Test Folder')); 237 | $this->assertEquals($testFolderNumStart - 1, $server->numMessages(), 'Message moved out of Test Folder.'); 238 | // Make sure Sent folder gains one 239 | $this->assertTrue($server->setMailBox('Sent')); 240 | $this->assertEquals($sentFolderNumStart + 1, $server->numMessages(), 'Message moved into Sent Folder.'); 241 | } 242 | 243 | public function testDecode() 244 | { 245 | $quotedPrintableDecoded = "Now's the time for all folk to come to the aid of their country."; 246 | $quotedPrintable = <<<'ENCODE' 247 | Now's the time = 248 | for all folk to come= 249 | to the aid of their country. 250 | ENCODE; 251 | $this->assertEquals($quotedPrintableDecoded, Message::decode($quotedPrintable, 'quoted-printable'), 'Decodes quoted printable'); 252 | $this->assertEquals($quotedPrintableDecoded, Message::decode($quotedPrintable, 4), 'Decodes quoted printable'); 253 | 254 | $testString = 'This is a test string'; 255 | $base64 = base64_encode($testString); 256 | $this->assertEquals($testString, Message::decode($base64, 'base64'), 'Decodes quoted base64'); 257 | $this->assertEquals($testString, Message::decode($base64, 3), 'Decodes quoted base64'); 258 | 259 | $notEncoded = '> w - www.somesite.com.au'; 260 | $this->assertEquals($notEncoded, Message::decode($notEncoded, 0), 'Nothing to decode'); 261 | } 262 | 263 | public function testTypeIdToString() 264 | { 265 | $types = array(); 266 | $types[0] = 'text'; 267 | $types[1] = 'multipart'; 268 | $types[2] = 'message'; 269 | $types[3] = 'application'; 270 | $types[4] = 'audio'; 271 | $types[5] = 'image'; 272 | $types[6] = 'video'; 273 | $types[7] = 'other'; 274 | $types[8] = 'other'; 275 | $types[32] = 'other'; 276 | 277 | foreach($types as $id => $type) 278 | $this->assertEquals($type, Message::typeIdToString($id)); 279 | } 280 | 281 | public function testGetParametersFromStructure() 282 | { 283 | 284 | } 285 | 286 | } 287 | -------------------------------------------------------------------------------- /vendor/tedivm/fetch/tests/Fetch/Test/ServerTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace Fetch\Test; 13 | 14 | use Fetch\Server; 15 | 16 | /** 17 | * @package Fetch 18 | * @author Robert Hafner 19 | */ 20 | class ServerTest extends \PHPUnit_Framework_TestCase 21 | { 22 | public static $num_messages_inbox = 12; 23 | 24 | /** 25 | * @dataProvider flagsDataProvider 26 | * @param string $expected server string with %host% placeholder 27 | * @param integer $port to use (needed to test behavior on port 143 and 993 from constructor) 28 | * @param array $flags to set/unset ($flag => $value) 29 | */ 30 | public function testFlags($expected, $port, $flags) 31 | { 32 | $server = new Server(TESTING_SERVER_HOST, $port); 33 | 34 | foreach ($flags as $flag => $value) { 35 | $server->setFlag($flag, $value); 36 | } 37 | 38 | $this->assertEquals(str_replace('%host%', TESTING_SERVER_HOST, $expected), $server->getServerString()); 39 | } 40 | 41 | public function testFlagOverwrite() 42 | { 43 | $server = static::getServer(); 44 | 45 | $server->setFlag('TestFlag', 'true'); 46 | $this->assertAttributeContains('TestFlag=true', 'flags', $server); 47 | 48 | $server->setFlag('TestFlag', 'false'); 49 | $this->assertAttributeContains('TestFlag=false', 'flags', $server); 50 | } 51 | 52 | public function flagsDataProvider() 53 | { 54 | return array( 55 | array('{%host%:143/novalidate-cert}', 143, array()), 56 | array('{%host%:143/validate-cert}', 143, array('validate-cert' => true)), 57 | array('{%host%:143}', 143, array('novalidate-cert' => false)), 58 | array('{%host%:993/ssl}', 993, array()), 59 | array('{%host%:993}', 993, array('ssl' => false)), 60 | array('{%host%:100/tls}', 100, array('tls' => true)), 61 | array('{%host%:100/tls}', 100, array('tls' => true, 'tls' => true)), 62 | array('{%host%:100/notls}', 100, array('tls' => true, 'notls' => true)), 63 | array('{%host%:100}', 100, array('ssl' => true, 'ssl' => false)), 64 | array('{%host%:100/user=foo}', 100, array('user' => 'foo')), 65 | array('{%host%:100/user=foo}', 100, array('user' => 'foo', 'user' => 'foo')), 66 | array('{%host%:100/user=bar}', 100, array('user' => 'foo', 'user' => 'bar')), 67 | array('{%host%:100}', 100, array('user' => 'foo', 'user' => false)), 68 | ); 69 | } 70 | 71 | /** 72 | * @dataProvider connectionDataProvider 73 | * @param integer $port to use (needed to test behavior on port 143 and 993 from constructor) 74 | * @param array $flags to set/unset ($flag => $value) 75 | * @param string $message Assertion message 76 | */ 77 | public function testConnection($port, $flags, $message) 78 | { 79 | $server = new Server(TESTING_SERVER_HOST, $port); 80 | $server->setAuthentication(TEST_USER, TEST_PASSWORD); 81 | 82 | foreach ($flags as $flag => $value) { 83 | $server->setFlag($flag, $value); 84 | } 85 | 86 | $imapSteam = $server->getImapStream(); 87 | $this->assertInternalType('resource', $imapSteam, $message); 88 | } 89 | 90 | public function connectionDataProvider() 91 | { 92 | return array( 93 | array(143, array(), 'Connects with default settings.'), 94 | array(993, array('novalidate-cert' => true), 'Connects over SSL (self signed).'), 95 | ); 96 | } 97 | 98 | public function testNumMessages() 99 | { 100 | $server = static::getServer(); 101 | $numMessages = $server->numMessages(); 102 | $this->assertEquals(self::$num_messages_inbox, $numMessages); 103 | $this->assertEquals(0, $server->numMessages( 'DOESNOTEXIST'.time() ) ); 104 | } 105 | 106 | public function testGetMessages() 107 | { 108 | $server = static::getServer(); 109 | $messages = $server->getMessages(5); 110 | 111 | $this->assertCount(5, $messages, 'Five messages returned'); 112 | foreach ($messages as $message) { 113 | $this->assertInstanceOf('\Fetch\Message', $message, 'Returned values are Messages'); 114 | } 115 | } 116 | 117 | public function testGetMessagesOrderedByDateAsc() 118 | { 119 | $server = static::getServer(); 120 | $messages = $server->getOrderedMessages(SORTDATE, false, 2); 121 | 122 | $this->assertCount(2, $messages, 'Two messages returned'); 123 | $this->assertGreaterThan($messages[0]->getDate(), $messages[1]->getDate(), 'Messages in ascending order'); 124 | } 125 | 126 | public function testGetMessagesOrderedByDateDesc() 127 | { 128 | $server = static::getServer(); 129 | $messages = $server->getOrderedMessages(SORTDATE, true, 2); 130 | 131 | $this->assertCount(2, $messages, 'Two messages returned'); 132 | $this->assertLessThan($messages[0]->getDate(), $messages[1]->getDate(), 'Messages in descending order'); 133 | } 134 | 135 | public function testGetMailBox() 136 | { 137 | $server = static::getServer(); 138 | $this->assertEquals('', $server->getMailBox()); 139 | $this->assertTrue($server->setMailBox('Sent')); 140 | $this->assertEquals('Sent', $server->getMailBox()); 141 | } 142 | 143 | public function testSetMailBox() 144 | { 145 | $server = static::getServer(); 146 | 147 | $this->assertTrue($server->setMailBox('Sent')); 148 | $this->assertEquals('Sent', $server->getMailBox()); 149 | 150 | $this->assertTrue($server->setMailBox('Flagged Email')); 151 | $this->assertEquals('Flagged Email', $server->getMailBox()); 152 | 153 | $this->assertFalse($server->setMailBox('Cheese')); 154 | 155 | $this->assertTrue($server->setMailBox('')); 156 | $this->assertEquals('', $server->getMailBox()); 157 | } 158 | 159 | public function testHasMailBox() 160 | { 161 | $server = static::getServer(); 162 | 163 | $this->assertTrue($server->hasMailBox('Sent'), 'Has mailbox "Sent"'); 164 | $this->assertTrue($server->hasMailBox('Flagged Email'), 'Has mailbox "Flagged Email"'); 165 | $this->assertFalse($server->hasMailBox('Cheese'), 'Does not have mailbox "Cheese"'); 166 | } 167 | 168 | public function testListMailBoxes() 169 | { 170 | $server = static::getServer(); 171 | $spec = sprintf('{%s:143/novalidate-cert}', TESTING_SERVER_HOST); 172 | 173 | $list = $server->listMailboxes('*'); 174 | $this->assertContains($spec.'Sent', $list, 'Has mailbox "Sent"'); 175 | $this->assertNotContains($spec.'Cheese', $list, 'Does not have mailbox "Cheese"'); 176 | } 177 | 178 | public function testCreateMailbox() 179 | { 180 | $server = static::getServer(); 181 | 182 | $this->assertFalse($server->hasMailBox('Cheese'), 'Does not have mailbox "Cheese"'); 183 | $this->assertTrue($server->createMailBox('Cheese'), 'createMailbox returns true.'); 184 | $this->assertTrue($server->hasMailBox('Cheese'), 'Mailbox "Cheese" was created'); 185 | } 186 | 187 | public function testDeleteMailbox() 188 | { 189 | $server = static::getServer(); 190 | $this->assertTrue($server->hasMailBox('Cheese'), 'Does have mailbox "Cheese"'); 191 | $this->assertTrue($server->deleteMailBox('Cheese'), 'deleteMailBox returns true.'); 192 | $this->assertFalse($server->hasMailBox('Cheese'), 'Mailbox "Cheese" was deleted'); 193 | } 194 | 195 | /** 196 | * @expectedException \RuntimeException 197 | */ 198 | public function testSetOptionsException() 199 | { 200 | $server = static::getServer(); 201 | $server->setOptions('purple'); 202 | } 203 | 204 | public function testSetOptions() 205 | { 206 | $server = static::getServer(); 207 | $server->setOptions(5); 208 | $this->assertAttributeEquals(5, 'options', $server); 209 | } 210 | 211 | public function testExpunge() 212 | { 213 | $server = static::getServer(); 214 | $message = $server->getMessageByUid(12); 215 | 216 | $this->assertInstanceOf('\Fetch\Message', $message, 'Message exists'); 217 | 218 | $message->delete(); 219 | 220 | $this->assertInstanceOf('\Fetch\Message', $server->getMessageByUid(12), 'Message still present after being deleted but before being expunged.'); 221 | 222 | $server->expunge(); 223 | 224 | $this->assertFalse($server->getMessageByUid(12), 'Message successfully expunged'); 225 | } 226 | 227 | public static function getServer() 228 | { 229 | $server = new Server(TESTING_SERVER_HOST, 143); 230 | $server->setAuthentication(TEST_USER, TEST_PASSWORD); 231 | 232 | return $server; 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /vendor/tedivm/fetch/tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | error_reporting(-1); 13 | 14 | define('TESTING', true); 15 | define('TEST_USER', 'testuser'); 16 | define('TEST_PASSWORD', 'applesauce'); 17 | 18 | date_default_timezone_set('UTC'); 19 | 20 | if (getenv('TRAVIS')) { 21 | define('TESTING_ENVIRONMENT', 'TRAVIS'); 22 | define('TESTING_SERVER_HOST', '127.0.0.1'); 23 | } else { 24 | define('TESTING_ENVIRONMENT', 'VAGRANT'); 25 | define('TESTING_SERVER_HOST', '172.31.1.2'); 26 | } 27 | 28 | $filename = __DIR__ .'/../vendor/autoload.php'; 29 | 30 | if (!file_exists($filename)) { 31 | echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" . PHP_EOL; 32 | echo " You need to execute `composer install` before running the tests. " . PHP_EOL; 33 | echo " Vendors are required for complete test execution. " . PHP_EOL; 34 | echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" . PHP_EOL . PHP_EOL; 35 | $filename = __DIR__ .'/../autoload.php'; 36 | require_once $filename; 37 | } else { 38 | $loader = require $filename; 39 | $loader->add('Fetch\\Test', __DIR__); 40 | } 41 | -------------------------------------------------------------------------------- /vendor/tedivm/fetch/tests/runTests.sh: -------------------------------------------------------------------------------- 1 | #/usr/bin/env/sh 2 | set -e 3 | 4 | if [ ! -n "$TRAVIS" ]; then 5 | ./vendor/tedivm/dovecottesting/SetupEnvironment.sh 6 | sleep 5 7 | fi 8 | 9 | echo 'Running unit tests.' 10 | ./vendor/bin/phpunit --verbose --coverage-clover build/logs/clover.xml 11 | 12 | echo '' 13 | echo '' 14 | echo '' 15 | echo 'Testing for Coding Styling Compliance.' 16 | echo 'All code should follow PSR standards.' 17 | ./vendor/bin/php-cs-fixer fix ./ --level="all" -vv --dry-run --------------------------------------------------------------------------------