├── .gitignore ├── .scrutinizer.yml ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── lib └── GameNet │ └── Jabber │ ├── Mixins │ ├── GroupTrait.php │ ├── RoomTrait.php │ ├── RosterTrait.php │ └── UserTrait.php │ └── RpcClient.php ├── phpunit.xml └── tests └── GameNet └── Jabber ├── GroupTest.php ├── RoomTest.php ├── RosterTest.php ├── RpcClientTest.php └── UserTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | build 3 | vendor 4 | composer.lock 5 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | paths: [lib/*] 3 | excluded_paths: [vendor/*, tests/*] 4 | 5 | before_commands: 6 | - 'composer install --dev' 7 | 8 | tools: 9 | external_code_coverage: 10 | timeout: 600 11 | php_code_coverage: true 12 | php_mess_detector: true 13 | php_code_sniffer: true 14 | sensiolabs_security_checker: true 15 | php_pdepend: true 16 | php_loc: 17 | enabled: true 18 | excluded_dirs: [vendor, tests] 19 | php_cpd: 20 | enabled: true 21 | excluded_dirs: [vendor, tests] 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.5 5 | 6 | before_script: 7 | - wget http://getcomposer.org/composer.phar 8 | - php composer.phar install --dev 9 | 10 | script: phpunit --coverage-text --exclude-group ProcessTitle 11 | 12 | after_script: 13 | - wget https://scrutinizer-ci.com/ocular.phar 14 | - php ocular.phar code-coverage:upload --format=php-clover ./build/coverage.clover 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 GameNet 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 all 13 | 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 THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # php-jabber-rpc # 2 | 3 | [![Build Status](https://travis-ci.org/gamenet/php-jabber-rpc.svg?branch=master)](https://travis-ci.org/gamenet/php-jabber-rpc) 4 | [![Latest Stable Version](https://poser.pugx.org/gamenet/php-jabber-rpc/v/stable.png)](https://packagist.org/packages/gamenet/php-jabber-rpc) 5 | [![Code Coverage](https://scrutinizer-ci.com/g/gamenet/php-jabber-rpc/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/gamenet/php-jabber-rpc/?branch=master) 6 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/gamenet/php-jabber-rpc/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/gamenet/php-jabber-rpc/?branch=master) 7 | [![Latest Unstable Version](https://poser.pugx.org/gamenet/php-jabber-rpc/v/unstable.png)](https://packagist.org/packages/gamenet/php-jabber-rpc) 8 | [![License](https://poser.pugx.org/gamenet/php-jabber-rpc/license.png)](https://packagist.org/packages/gamenet/php-jabber-rpc) 9 | 10 | # About # 11 | 12 | [mod_xmlrpc](http://www.ejabberd.im/ejabberd+integration+with+XMLRPC+API) is a module for [ejabberd](http://www.ejabberd.im/), 13 | a XMPP/Jabber server written in Erlang. It starts a XML-RPC server and waits for external requests. Implemented calls include 14 | statistics and user administration. This allows external programs written in any language like websites or administrative tools 15 | to communicate with ejabberd to get information or to make changes without the need to know ejabberd internals. 16 | 17 | One example usage is a corporate site in PHP that creates a Jabber user every time a new user is created on the website. Some 18 | benefits of interfacing with the Jabber server by XML-RPC instead of modifying directly the database are: 19 | 20 | * external programs are more simple and easy to develop and debug 21 | * can communicate with a server in a different machine, and even on Internet 22 | 23 | This library is an simple wrapper above php xmlrpc module to simplify ejabberd mod_xmlrpc usage from php. PHP code based 24 | on [mod_admin_extra.erl](https://github.com/processone/ejabberd-contrib/blob/master/mod_admin_extra/src/mod_admin_extra.erl) 25 | and [mod_muc_admin.erl](https://github.com/processone/ejabberd-contrib/blob/master/mod_muc_admin/src/mod_muc_admin.erl) 26 | source files. 27 | 28 | ## Requirements ## 29 | 30 | PHP >= 5.4 31 | 32 | ## Installation ## 33 | 34 | ### Composer ### 35 | The recommended way to install library is [composer](http://getcomposer.org). 36 | You can see [package information on Packagist](https://packagist.org/packages/gamenet/php-jabber-rpc). 37 | 38 | ```JSON 39 | { 40 | "require": { 41 | "gamenet/php-jabber-rpc": "*" 42 | } 43 | } 44 | ``` 45 | 46 | ### Do not use composer? ### 47 | Just clone the repository and take care about autoload for namespace `GameNet`. 48 | 49 | # Usage # 50 | 51 | Basic usage looks like this: 52 | 53 | ```php 54 | $rpc = new \GameNet\Jabber\RpcClient([ 55 | 'server' => 'http://127.0.0.1:4560', 56 | 'host' => 'j.gamenet.ru', 57 | 'debug' => false, 58 | ]); 59 | 60 | //Create 2 new users with name `Ivan` and `Petr` with password `someStrongPassword` 61 | $rpc->createUser('Ivan', 'someStrongPassword'); 62 | $rpc->createUser('Petr', 'someStrongPassword'); 63 | 64 | // Add each other in the contact list with group 'Friend' 65 | $rpc->addRosterItem('Ivan', 'Petr', 'Petr Ivanov', 'Friend'); 66 | $rpc->addRosterItem('Petr', 'Ivan', 'Ivan Petrov', 'Friend'); 67 | 68 | // Get contact list Ivan 69 | $contacts = $rpc->getRoster($username); 70 | ``` -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gamenet/php-jabber-rpc", 3 | "type": "library", 4 | "description": "PHP wrapper for ejabberd xml-rpc module", 5 | "keywords": ["xmpp", "jabber", "ejabberd", "xml-rpc", "xml", "rpc", "wrapper"], 6 | "homepage": "https://github.com/gamenet/php-jabber-rpc", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Vadim Sabirov", 11 | "email": "pr0head@gmail.com" 12 | }, 13 | { 14 | "name": "Nikolay Bondarenko", 15 | "email": "misterionkell@gmail.com" 16 | } 17 | ], 18 | "require": { 19 | "php": ">=5.4.0", 20 | "comodojo/xmlrpc": "~1.1" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": ">=4.0.0" 24 | }, 25 | "autoload": { 26 | "psr-0": { 27 | "GameNet": "lib/" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/GameNet/Jabber/Mixins/GroupTrait.php: -------------------------------------------------------------------------------- 1 | 30 | * @license MIT http://opensource.org/licenses/MIT 31 | */ 32 | namespace GameNet\Jabber\Mixins; 33 | 34 | /** 35 | * Class GroupTrait 36 | * 37 | * @package GameNet\Jabber 38 | * @copyright Copyright (с) 2014, GameNet. All rights reserved. 39 | * @author Vadim Sabirov 40 | * @version 1.0 41 | */ 42 | trait GroupTrait 43 | { 44 | abstract protected function sendRequest($command, array $params); 45 | 46 | /** 47 | * Create a Shared Roster Group. 48 | * 49 | * @param string $groupId 50 | * @param string $name 51 | * @param string $description 52 | * @param array $display 53 | */ 54 | function createSharedRosterGroup($groupId, $name, $description = '', array $display = []) 55 | { 56 | $this->sendRequest( 57 | 'srg_create', 58 | [ 59 | 'host' => $this->host, 60 | 'group' => (string) $groupId, 61 | 'name' => $name, 62 | 'description' => $description, 63 | 'display' => join("\\n", array_merge([$groupId], $display)), 64 | ] 65 | ); 66 | } 67 | 68 | /** 69 | * Delete a Shared Roster Group 70 | * 71 | * @param string $groupId 72 | */ 73 | function deleteSharedRosterGroup($groupId) 74 | { 75 | $this->sendRequest( 76 | 'srg_delete', 77 | [ 78 | 'host' => $this->host, 79 | 'group' => $groupId, 80 | ] 81 | ); 82 | } 83 | 84 | /** 85 | * Get members of a Shared Roster Group 86 | * 87 | * @param string $groupId 88 | * 89 | * @return array ['jid1', 'jid2', ...] 90 | */ 91 | function getMembersSharedRosterGroup($groupId) 92 | { 93 | $response = $this->sendRequest( 94 | 'srg_get_members', 95 | [ 96 | 'host' => $this->host, 97 | 'group' => $groupId, 98 | ] 99 | ); 100 | 101 | if (!isset($response['members']) || empty($response['members'])) { 102 | return []; 103 | } 104 | 105 | $members = []; 106 | foreach ($response['members'] as $member) { 107 | $members[] = $member['member']; 108 | } 109 | 110 | return $members; 111 | } 112 | 113 | /** 114 | * Add the JID user@host to the Shared Roster Group 115 | * 116 | * @param string $user 117 | * @param string $groupId 118 | */ 119 | function addUserToSharedRosterGroup($user, $groupId) 120 | { 121 | return $this->sendRequest( 122 | 'srg_user_add', 123 | [ 124 | 'user' => $user, 125 | 'host' => $this->host, 126 | 'group' => $groupId, 127 | 'grouphost' => $this->host, 128 | ] 129 | ); 130 | } 131 | 132 | /** 133 | * Delete this JID user@host from the Shared Roster Group 134 | * 135 | * @param string $user 136 | * @param string $groupId 137 | */ 138 | function deleteUserSharedRosterGroup($user, $groupId) 139 | { 140 | return $this->sendRequest( 141 | 'srg_user_del', 142 | [ 143 | 'user' => $user, 144 | 'host' => $this->host, 145 | 'group' => $groupId, 146 | 'grouphost' => $this->host, 147 | ] 148 | ); 149 | } 150 | 151 | /** 152 | * List the Shared Roster Groups in Host 153 | * 154 | * @return array ['group1', 'group2', ...] 155 | */ 156 | function listSharedRosterGroups() 157 | { 158 | $response = $this->sendRequest( 159 | 'srg_list', 160 | ['host' => $this->host] 161 | ); 162 | 163 | if (!isset($response['groups']) || empty($response['groups'])) { 164 | return []; 165 | } 166 | 167 | $sharedGroups = []; 168 | foreach ($response['groups'] as $group) { 169 | $sharedGroups[] = $group['id']; 170 | } 171 | 172 | return $sharedGroups; 173 | } 174 | 175 | /** 176 | * @param string $groupId 177 | * 178 | * @return array ['name' => '...', 'description' => '...', 'displayed_groups' => ['...', '...']] 179 | */ 180 | public function getInfoSharedRosterGroup($groupId) 181 | { 182 | $response = $this->sendRequest( 183 | 'srg_get_info', 184 | [ 185 | 'host' => $this->host, 186 | 'group' => $groupId, 187 | ] 188 | ); 189 | 190 | if (!isset($response['informations']) || empty($response['informations'])) { 191 | return []; 192 | } 193 | 194 | $info = []; 195 | foreach ($response['informations'] as $element) { 196 | $key = $element['information'][0]['key']; 197 | $value = str_replace(['[', ']', '<<"', '">>'], '', $element['information'][1]['value']); 198 | $info[$key] = ($key === 'displayed_groups') ? explode(',', $value) : $value; 199 | } 200 | 201 | return $info; 202 | } 203 | } -------------------------------------------------------------------------------- /lib/GameNet/Jabber/Mixins/RoomTrait.php: -------------------------------------------------------------------------------- 1 | 30 | * @license MIT http://opensource.org/licenses/MIT 31 | */ 32 | namespace GameNet\Jabber\Mixins; 33 | 34 | /** 35 | * Class RoomTrait 36 | * 37 | * @package GameNet\Jabber 38 | * @copyright Copyright (с) 2014, GameNet. All rights reserved. 39 | * @author Vadim Sabirov 40 | * @version 1.0 41 | */ 42 | trait RoomTrait 43 | { 44 | abstract protected function sendRequest($command, array $params); 45 | 46 | /** 47 | * Create a MUC room name@service in host. 48 | * 49 | * @param string $name 50 | */ 51 | public function createRoom($name) 52 | { 53 | $this->sendRequest( 54 | 'create_room', 55 | [ 56 | 'name' => $name, 57 | 'service' => 'conference.' . $this->host, 58 | 'host' => $this->host, 59 | ] 60 | ); 61 | } 62 | 63 | /** 64 | * Send a direct invitation to several destinations. 65 | * 66 | * Password and Message can also be: none. Users JIDs are separated with `:` 67 | * 68 | * @param string $name The room name. 69 | * @param string $password The room password. 70 | * @param string $reason The invitation text which be sent to users. 71 | * @param array $users The users JIDs invited to room. 72 | */ 73 | public function inviteToRoom($name, $password, $reason, array $users) 74 | { 75 | $this->sendRequest( 76 | 'send_direct_invitation', 77 | [ 78 | 'room' => $name . '@conference.' . $this->host, 79 | 'password' => $password, 80 | 'reason' => $reason, 81 | 'users' => join(':', $users), 82 | ] 83 | ); 84 | } 85 | 86 | /** 87 | * Delete a MUC room. 88 | * 89 | * @param string $name The room name. 90 | */ 91 | public function deleteRoom($name) 92 | { 93 | $this->sendRequest( 94 | 'destroy_room', 95 | [ 96 | 'name' => $name, 97 | 'service' => 'conference.' . $this->host, 98 | 'host' => $this->host, 99 | ] 100 | ); 101 | } 102 | 103 | /** 104 | * List existing rooms. 105 | * 106 | * @return array Return array like ['room1@conference.j.test.dev', 'room2@conference.j.test.dev', ...] 107 | */ 108 | public function getOnlineRooms() 109 | { 110 | $rooms = $this->sendRequest( 111 | 'muc_online_rooms', 112 | ['host' => $this->host] 113 | ); 114 | 115 | if (!isset($rooms['rooms']) || empty($rooms['rooms'])) { 116 | return []; 117 | } 118 | 119 | $roomList = []; 120 | foreach ($rooms['rooms'] as $item) { 121 | $roomList[] = $item['room']; 122 | } 123 | 124 | return $roomList; 125 | } 126 | 127 | /** 128 | * Change an option in a MUC room. 129 | * 130 | * @param string $name The room name 131 | * @param string $option Valid values: 132 | * title (string) 133 | * password (string) 134 | * password_protected (bool) 135 | * anonymous (bool) 136 | * max_users (int) 137 | * allow_change_subj (bool) 138 | * allow_query_users (bool) 139 | * allow_private_messages (bool) 140 | * public (bool) 141 | * public_list (bool) 142 | * persistent (bool) 143 | * moderated (bool) 144 | * members_by_default (bool) 145 | * members_only (bool) 146 | * allow_user_invites (bool) 147 | * logging (bool) 148 | * @param string $value 149 | */ 150 | public function setRoomOption($name, $option, $value) 151 | { 152 | $value = !is_bool($value) ? $value : ($value ? 'true' : 'false'); 153 | 154 | $this->sendRequest( 155 | 'change_room_option', 156 | [ 157 | 'name' => $name, 158 | 'service' => 'conference.' . $this->host, 159 | 'option' => $option, 160 | 'value' => (string) $value, 161 | ] 162 | ); 163 | } 164 | 165 | /** 166 | * Change an affiliation in a MUC room. 167 | * 168 | * @param string $name The room name. 169 | * @param string $userJid 170 | * @param string $affiliation Valid values: outcast, none, member, admin, owner 171 | * If the affiliation is 'none', the action is to remove 172 | */ 173 | public function setRoomAffiliation($name, $userJid, $affiliation) 174 | { 175 | $this->sendRequest( 176 | 'set_room_affiliation', 177 | [ 178 | 'name' => $name, 179 | 'service' => 'conference.' . $this->host, 180 | 'jid' => $userJid, 181 | 'affiliation' => $affiliation, 182 | ] 183 | ); 184 | } 185 | } -------------------------------------------------------------------------------- /lib/GameNet/Jabber/Mixins/RosterTrait.php: -------------------------------------------------------------------------------- 1 | 30 | * @license MIT http://opensource.org/licenses/MIT 31 | */ 32 | namespace GameNet\Jabber\Mixins; 33 | 34 | /** 35 | * Class RosterTrait 36 | * 37 | * @package GameNet\Jabber 38 | * @copyright Copyright (с) 2014, GameNet. All rights reserved. 39 | * @author Vadim Sabirov 40 | * @version 1.0 41 | */ 42 | trait RosterTrait 43 | { 44 | abstract protected function sendRequest($command, array $params); 45 | 46 | /** 47 | * Retrieve the roster for a given user. Returns a list of the contacts in a user roster. It also returns the state 48 | * of the contact subscription. Subscription can be either "none", "from", "to", "both". Pending can be "in", "out" 49 | * or "none". 50 | * 51 | * @param string $user 52 | * 53 | * @return array [['jid', 'nick', 'subscription', 'ask', 'group'], [], ...] 54 | */ 55 | public function getRoster($user) 56 | { 57 | $response = $this->sendRequest( 58 | 'get_roster', 59 | [ 60 | 'user' => $user, 61 | 'host' => $this->host, 62 | ] 63 | ); 64 | 65 | if (!isset($response['contacts']) || empty($response['contacts'])) { 66 | return []; 67 | } 68 | 69 | $rosterContacts = []; 70 | foreach ($response['contacts'] as $item) { 71 | $contact = []; 72 | foreach ($item['contact'] as $data) { 73 | foreach ($data as $key => $value) { 74 | $contact[$key] = $value; 75 | } 76 | } 77 | $rosterContacts[] = $contact; 78 | } 79 | 80 | return $rosterContacts; 81 | } 82 | 83 | /** 84 | * Add an item to a user's roster (supports ODBC). 85 | * 86 | * Subs is the state of the roster item subscription. It can be either `both`, `to`, `from` or `none`. `None` means 87 | * that presence packets are not send between parties. `Both` means that presence packets are send in both direction. 88 | * `To` means that the user see the presence of the given nickname. `From` means that the nickname specified sees the 89 | * user presence. 90 | * 91 | * Do not forget that roster items should be kept symmetric: when adding a roster item for a user, you have to do 92 | * the symmetric roster item addition. 93 | * 94 | * @param string $user 95 | * @param string $contact 96 | * @param string $nickname 97 | * @param string $group 98 | * @param string $subs Available: none, from, to or both 99 | */ 100 | public function addRosterItem($user, $contact, $nickname, $group = '', $subs = 'both') 101 | { 102 | $this->sendRequest( 103 | 'add_rosteritem', 104 | [ 105 | 'localuser' => $user, 106 | 'localserver' => $this->host, 107 | 'user' => $contact, 108 | 'server' => $this->host, 109 | 'nick' => $nickname, 110 | 'group' => $group, 111 | 'subs' => $subs, 112 | ] 113 | ); 114 | } 115 | 116 | /** 117 | * Delete an item from a user's roster (supports ODBC). 118 | * 119 | * Do not forget that roster items should be kept symmetric: when removing a roster item for a user, you have to do 120 | * the symmetric roster item removal. This mechanism bypass the standard roster approval addition mechanism and 121 | * should only be used for server administration or server integration purpose. 122 | * 123 | * @param string $localUser The roster owner. 124 | * @param string $localUser The roster owner. 125 | * @param string $user Roster user item which would be deleted. 126 | */ 127 | public function deleteRosterItem($localUser, $user) 128 | { 129 | $this->sendRequest( 130 | 'delete_rosteritem', 131 | [ 132 | 'localuser' => $localUser, 133 | 'localserver' => $this->host, 134 | 'user' => $user, 135 | 'server' => $this->host, 136 | ] 137 | ); 138 | } 139 | } -------------------------------------------------------------------------------- /lib/GameNet/Jabber/Mixins/UserTrait.php: -------------------------------------------------------------------------------- 1 | 30 | * @license MIT http://opensource.org/licenses/MIT 31 | */ 32 | namespace GameNet\Jabber\Mixins; 33 | 34 | /** 35 | * Class UserTrait 36 | * 37 | * @category GGS 38 | * @package GameNet\Jabber 39 | * @copyright Copyright (с) 2014, GameNet. All rights reserved. 40 | * @author Vadim Sabirov 41 | * @version 1.0 42 | */ 43 | trait UserTrait 44 | { 45 | abstract protected function sendRequest($command, array $params); 46 | 47 | /** 48 | * Create an ejabberd user account. 49 | * 50 | * @param string $user 51 | * @param string $password 52 | * 53 | * @throws \RuntimeException 54 | */ 55 | public function createUser($user, $password) 56 | { 57 | $response = $this->sendRequest( 58 | 'register', 59 | [ 60 | 'host' => $this->host, 61 | 'user' => $user, 62 | 'password' => $password 63 | ] 64 | ); 65 | 66 | if ($response['res'] != 0) { 67 | throw new \RuntimeException('Unable create user'); 68 | } 69 | } 70 | 71 | /** 72 | * Check if ejabberd user account already exists. 73 | * 74 | * @param string $user 75 | * 76 | * @return bool 77 | */ 78 | public function checkAccount($user) 79 | { 80 | $response = $this->sendRequest( 81 | 'check_account', 82 | [ 83 | 'user' => $user, 84 | 'host' => $this->host 85 | ] 86 | ); 87 | 88 | return $response['res'] == 0; 89 | } 90 | 91 | /** 92 | * Change the password on behalf of the given user. 93 | * 94 | * @param string $user 95 | * @param string $password 96 | */ 97 | public function changePassword($user, $password) 98 | { 99 | $this->sendRequest( 100 | 'change_password', 101 | [ 102 | 'host' => $this->host, 103 | 'user' => $user, 104 | 'newpass' => $password 105 | ] 106 | ); 107 | } 108 | 109 | /** 110 | * Define user nickname. 111 | * 112 | * The nickname is set/updated in the user Vcard. Other informations are unchanged. 113 | * 114 | * @param string $user 115 | * @param string $nickname 116 | */ 117 | public function setNickname($user, $nickname) 118 | { 119 | $this->sendRequest( 120 | 'set_nickname', 121 | [ 122 | 'host' => $this->host, 123 | 'user' => $user, 124 | 'nickname' => $nickname 125 | ] 126 | ); 127 | } 128 | 129 | /** 130 | * Get last activity information 131 | * 132 | * Timestamp is the seconds since 1970-01-01 00:00:00 UTC, for example: date +%s 133 | * 134 | * @param string $user 135 | * 136 | * @return string 137 | */ 138 | public function getLastActivity($user) 139 | { 140 | $response = $this->sendRequest( 141 | 'get_last', 142 | [ 143 | 'host' => $this->host, 144 | 'user' => $user, 145 | ] 146 | ); 147 | 148 | return $response['last_activity']; 149 | } 150 | 151 | /** 152 | * Send a chat message to a local or remote bare of full JID 153 | * 154 | * @param string $fromJid 155 | * @param string $toJid 156 | * @param string $message 157 | */ 158 | public function sendMessageChat($fromJid, $toJid, $message) 159 | { 160 | $this->sendRequest( 161 | 'send_message_chat', 162 | [ 163 | 'from' => $fromJid, 164 | 'to' => $toJid, 165 | 'body' => $message 166 | ] 167 | ); 168 | } 169 | 170 | /** 171 | * Unregister an ejabberd user account. This mechanism should only be used for server administration or server 172 | * integration purpose. 173 | * 174 | * @param string $user 175 | */ 176 | public function unregisterUser($user) 177 | { 178 | $this->sendRequest( 179 | 'unregister', 180 | [ 181 | 'host' => $this->host, 182 | 'user' => $user, 183 | ] 184 | ); 185 | } 186 | 187 | /** 188 | * Set user status with message 189 | * 190 | * @param string $user 191 | * @param string $show Valid values are: away, chat, dnd, xa 192 | * @param string $status Text message 193 | * @param int $priority The value MUST be an integer between -128 and +127 194 | */ 195 | public function setStatus($user, $show, $status, $priority) 196 | { 197 | $priority = (string) $priority; 198 | $stanza = " 199 | 200 | $show 201 | $status 202 | $priority 203 | "; 204 | 205 | $this->sendStanzaC2S($user, $stanza); 206 | } 207 | 208 | /** 209 | * Get information about all sessions of a user 210 | * 211 | * @param string $user 212 | * 213 | * @return array [['connection', 'ip', 'port', 'priority', 'node', 'uptime', 'status', 'resource', 'statustext'], [], ...] 214 | */ 215 | public function userSessionsInfo($user) 216 | { 217 | $response = $this->sendRequest( 218 | 'user_sessions_info', 219 | [ 220 | 'host' => $this->host, 221 | 'user' => $user, 222 | ] 223 | ); 224 | 225 | if (!isset($response['sessions_info']) || empty($response['sessions_info'])) { 226 | return []; 227 | } 228 | 229 | $sessions = []; 230 | foreach ($response['sessions_info'] as $info) { 231 | $session = []; 232 | foreach ($info['session'] as $data) { 233 | foreach ($data as $key => $value) { 234 | $session[$key] = $value; 235 | } 236 | } 237 | $sessions[] = $session; 238 | } 239 | 240 | return $sessions; 241 | } 242 | 243 | /** 244 | * Get content from a vCard field 245 | * 246 | * @param string $user 247 | * @param string $name 248 | * 249 | * @return string 250 | */ 251 | public function getVCard($user, $name) 252 | { 253 | if (strstr($name, ' ')) { 254 | $command = 'get_vcard2'; 255 | list($name, $subname) = explode(' ', $name); 256 | 257 | $params = [ 258 | 'host' => $this->host, 259 | 'user' => $user, 260 | 'name' => $name, 261 | 'subname' => $subname, 262 | ]; 263 | } else { 264 | $command = 'get_vcard'; 265 | $params = [ 266 | 'host' => $this->host, 267 | 'user' => $user, 268 | 'name' => $name, 269 | ]; 270 | } 271 | 272 | try { 273 | $response = $this->sendRequest($command, $params); 274 | } catch (\RuntimeException $e) { 275 | return ''; 276 | } 277 | 278 | return $response['content']; 279 | } 280 | 281 | /** 282 | * Set content in a vCard field 283 | * 284 | * @param string $user 285 | * @param string $name 286 | * @param string $value 287 | */ 288 | public function setVCard($user, $name, $value) 289 | { 290 | if (strstr($name, ' ')) { 291 | $command = 'set_vcard2'; 292 | list($name, $subname) = explode(' ', $name); 293 | 294 | $params = [ 295 | 'host' => $this->host, 296 | 'user' => $user, 297 | 'name' => $name, 298 | 'subname' => $subname, 299 | 'content' => $value, 300 | ]; 301 | } else { 302 | $command = 'set_vcard'; 303 | $params = [ 304 | 'host' => $this->host, 305 | 'user' => $user, 306 | 'name' => $name, 307 | 'content' => $value, 308 | ]; 309 | } 310 | 311 | $this->sendRequest($command, $params); 312 | } 313 | 314 | /** 315 | * Ban an account: kick sessions and set random password 316 | * 317 | * @param string $user 318 | * @param string $reason 319 | */ 320 | public function banAccount($user, $reason) 321 | { 322 | $this->sendRequest( 323 | 'ban_account', 324 | [ 325 | 'host' => $this->host, 326 | 'user' => $user, 327 | 'reason' => $reason, 328 | ] 329 | ); 330 | } 331 | 332 | /** 333 | * Send a stanza as if sent from a c2s session 334 | * 335 | * @param string $user 336 | * @param string $stanza XML string 337 | */ 338 | public function sendStanzaC2S($user, $stanza) 339 | { 340 | $sessions = $this->userSessionsInfo($user); 341 | foreach ($sessions as $session) { 342 | $stanza = str_replace('{resource}', $session['resource'], $stanza); 343 | $this->sendRequest( 344 | 'send_stanza_c2s', 345 | [ 346 | 'host' => $this->host, 347 | 'user' => $user, 348 | 'resource' => $session['resource'], 349 | 'stanza' => $stanza, 350 | ] 351 | ); 352 | } 353 | } 354 | 355 | /** 356 | * Set groups for contact in roster user owner 357 | * 358 | * @deprecated 359 | * @param string $user 360 | * @param string $contact 361 | * @param array $groups 362 | */ 363 | public function setGroupForUserRoster($user, $contact, array $groups) 364 | { 365 | $id = uniqid(); 366 | $userJid = "$user@$this->host"; 367 | $contactJid = "$contact@$this->host"; 368 | $groupList = ''; 369 | foreach ($groups as $group) { 370 | $groupList .= "$group"; 371 | } 372 | 373 | $stanza = " 374 | 375 | 376 | $groupList 377 | 378 | "; 379 | 380 | $this->sendStanzaC2S($user, $stanza); 381 | } 382 | 383 | /** 384 | * Add jid to a group in a user's roster (supports ODBC) 385 | * 386 | * WARNING! 387 | * This method uses commands that are not available in the basic version eJabberd 388 | * These commands are available in the branch version https://github.com/gamenet/ejabberd 389 | * See request to add features - https://github.com/gamenet/ejabberd/pull/11 390 | * 391 | * @param $user 392 | * @param $contact 393 | * @param $group 394 | */ 395 | public function addUserToGroup($user, $contact, $group) 396 | { 397 | $this->sendRequest( 398 | 'add_jid_to_group', 399 | [ 400 | 'localserver' => $this->host, 401 | 'localuser' => $user, 402 | 'jid' => "$contact@$this->host", 403 | 'group' => $group, 404 | ] 405 | ); 406 | } 407 | 408 | /** 409 | * Delete a jid from a user's roster group (supports ODBC) 410 | * 411 | * WARNING! 412 | * This method uses commands that are not available in the basic version eJabberd 413 | * These commands are available in the branch version https://github.com/gamenet/ejabberd 414 | * See request to add features - https://github.com/gamenet/ejabberd/pull/11 415 | * 416 | * 417 | * @param $user 418 | * @param $contact 419 | * @param $group 420 | */ 421 | public function deleteUserFromGroup($user, $contact, $group) 422 | { 423 | $this->sendRequest( 424 | 'delete_jid_from_group', 425 | [ 426 | 'localserver' => $this->host, 427 | 'localuser' => $user, 428 | 'jid' => "$contact@$this->host", 429 | 'group' => $group, 430 | 'deleteroster' => "false", 431 | ] 432 | ); 433 | } 434 | 435 | /** 436 | * Get list of connected users 437 | * 438 | * @return string 439 | */ 440 | public function getConnectedUsers() 441 | { 442 | $users = $this->sendRequest('connected_users', []); 443 | 444 | return isset($users['connected_users']) ? $users['connected_users'] : []; 445 | } 446 | } -------------------------------------------------------------------------------- /lib/GameNet/Jabber/RpcClient.php: -------------------------------------------------------------------------------- 1 | 30 | * @license MIT http://opensource.org/licenses/MIT 31 | */ 32 | namespace GameNet\Jabber; 33 | 34 | use Comodojo\Xmlrpc\XmlrpcDecoder; 35 | 36 | /** 37 | * Class RpcClient 38 | * 39 | * @package GameNet\Jabber 40 | * @copyright Copyright (с) 2014, GameNet. All rights reserved. 41 | * @author Vadim Sabirov 42 | * @version 1.0 43 | */ 44 | class RpcClient 45 | { 46 | use Mixins\UserTrait; 47 | use Mixins\GroupTrait; 48 | use Mixins\RoomTrait; 49 | use Mixins\RosterTrait; 50 | 51 | const VCARD_FULLNAME = 'FN'; 52 | const VCARD_NICKNAME = 'NICKNAME'; 53 | const VCARD_BIRTHDAY = 'BDAY'; 54 | const VCARD_EMAIL = 'EMAIL USERID'; 55 | const VCARD_COUNTRY = 'ADR CTRY'; 56 | const VCARD_CITY = 'ADR LOCALITY'; 57 | const VCARD_DESCRIPTION = 'DESC'; 58 | const VCARD_AVATAR_URL = 'EXTRA PHOTOURL'; 59 | 60 | const RESPONSE_MAX_LENGTH = 10000000; 61 | 62 | /** 63 | * @var string 64 | */ 65 | protected $server; 66 | /** 67 | * @var string 68 | */ 69 | protected $host; 70 | /** 71 | * @var bool 72 | */ 73 | protected $debug; 74 | /** 75 | * @var int 76 | */ 77 | protected $timeout; 78 | /** 79 | * @var string 80 | */ 81 | protected $username; 82 | /** 83 | * @var string 84 | */ 85 | protected $password; 86 | /** 87 | * @var string 88 | */ 89 | protected $userAgent; 90 | 91 | public function __construct(array $options) 92 | { 93 | if (!isset($options['server'])) { 94 | throw new \InvalidArgumentException("Parameter 'server' is not specified"); 95 | } 96 | 97 | if (!isset($options['host'])) { 98 | throw new \InvalidArgumentException("Parameter 'host' is not specified"); 99 | } 100 | 101 | $this->server = $options['server']; 102 | $this->host = $options['host']; 103 | $this->username = isset($options['username']) ? $options['username'] : ''; 104 | $this->password = isset($options['password']) ? $options['password'] : ''; 105 | $this->debug = isset($options['debug']) ? (bool)$options['debug'] : false; 106 | $this->timeout = isset($options['timeout']) ? (int)$options['timeout'] : 5; 107 | $this->userAgent = isset($options['userAgent']) ? $options['userAgent'] : 'GameNet'; 108 | 109 | if ($this->username && !$this->password) { 110 | throw new \InvalidArgumentException("Password cannot be empty if username was defined"); 111 | } 112 | if (!$this->username && $this->password) { 113 | throw new \InvalidArgumentException("Username cannot be empty if password was defined"); 114 | } 115 | } 116 | 117 | /** 118 | * @param int $timeout 119 | * @return $this 120 | */ 121 | public function setTimeout($timeout) 122 | { 123 | if (!is_int($timeout) || $timeout < 0) { 124 | throw new \InvalidArgumentException('Timeout value must be integer'); 125 | } 126 | 127 | $this->timeout = $timeout; 128 | 129 | return $this; 130 | } 131 | 132 | /** 133 | * @return int 134 | */ 135 | public function getTimeout() 136 | { 137 | return $this->timeout; 138 | } 139 | 140 | /** 141 | * @param string $userAgent 142 | * @return $this 143 | */ 144 | public function setUserAgent($userAgent) 145 | { 146 | $this->userAgent = $userAgent; 147 | 148 | return $this; 149 | } 150 | 151 | protected function sendRequest($command, array $params) 152 | { 153 | if ($this->username && $this->password) { 154 | $params = [ 155 | ['user' => $this->username, 'server' => $this->server, 'password' => $this->password], $params 156 | ]; 157 | } 158 | 159 | $request = xmlrpc_encode_request($command, $params, ['encoding' => 'utf-8', 'escaping' => 'markup']); 160 | 161 | $ch = curl_init(); 162 | curl_setopt($ch, CURLOPT_URL, $this->server); 163 | curl_setopt($ch, CURLOPT_FAILONERROR, 1); 164 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); 165 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 166 | curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); 167 | curl_setopt($ch, CURLOPT_HEADER, false); 168 | curl_setopt($ch, CURLOPT_POST, true); 169 | curl_setopt($ch, CURLOPT_POSTFIELDS, $request); 170 | curl_setopt($ch, CURLOPT_HTTPHEADER, ['User-Agent: ' . $this->userAgent, 'Content-Type: text/xml']); 171 | 172 | $response = curl_exec($ch); 173 | curl_close($ch); 174 | 175 | // INFO: We must use a custom parser instead xmlrpc_decode if the answer is longer than 10000000 bytes 176 | if (strlen($response) > self::RESPONSE_MAX_LENGTH) { 177 | $xml = (new XmlrpcDecoder)->decodeResponse($response); 178 | } else { 179 | $xml = \xmlrpc_decode($response); 180 | } 181 | 182 | if (!$xml || \xmlrpc_is_fault($xml)) { 183 | throw new \RuntimeException("Error execution command '$command'' with parameters " . var_export($params, true) . ". Response: "); 184 | } 185 | 186 | if ($this->debug) { 187 | var_dump($command, $params, $response); 188 | } 189 | 190 | return $xml; 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | tests 15 | 16 | 17 | 18 | 19 | 20 | src 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/GameNet/Jabber/GroupTest.php: -------------------------------------------------------------------------------- 1 | 8 | * @version 1.0 9 | */ 10 | class GroupTest extends PHPUnit_Framework_TestCase 11 | { 12 | private $mock; 13 | 14 | public function setUp() 15 | { 16 | $this->mock = $this->getMockBuilder('\GameNet\Jabber\RpcClient') 17 | ->disableOriginalConstructor() 18 | ->setMethods(['sendRequest']) 19 | ->getMock(); 20 | } 21 | 22 | public function testCreateGroup() 23 | { 24 | $this->mock->expects($this->once()) 25 | ->method('sendRequest') 26 | ->with($this->equalTo('srg_create')); 27 | 28 | $this->mock->createSharedRosterGroup('groupId', 'name', 'description'); 29 | } 30 | 31 | public function testDeleteGroup() 32 | { 33 | $this->mock->expects($this->once()) 34 | ->method('sendRequest') 35 | ->with($this->equalTo('srg_delete')); 36 | 37 | $this->mock->deleteSharedRosterGroup('groupId'); 38 | } 39 | 40 | public function testGetGroupMembers() 41 | { 42 | $this->mock->expects($this->once()) 43 | ->method('sendRequest') 44 | ->with($this->equalTo('srg_get_members')); 45 | 46 | $this->mock->getMembersSharedRosterGroup('groupId'); 47 | } 48 | 49 | public function testAddUserToGroup() 50 | { 51 | $this->mock->expects($this->once()) 52 | ->method('sendRequest') 53 | ->with($this->equalTo('srg_user_add')); 54 | 55 | $this->mock->addUserToSharedRosterGroup('groupId', 'name'); 56 | } 57 | 58 | public function testRemoveUserFromGroup() 59 | { 60 | $this->mock->expects($this->once()) 61 | ->method('sendRequest') 62 | ->with($this->equalTo('srg_user_del')); 63 | 64 | $this->mock->deleteUserSharedRosterGroup('groupId', 'name'); 65 | } 66 | 67 | public function testGetSharedGroups() 68 | { 69 | $this->mock->expects($this->once()) 70 | ->method('sendRequest') 71 | ->with($this->equalTo('srg_list')); 72 | 73 | $this->mock->listSharedRosterGroups(); 74 | } 75 | 76 | public function testGetInfoSharedRosterGroup() 77 | { 78 | $this->mock->expects($this->once()) 79 | ->method('sendRequest') 80 | ->with($this->equalTo('srg_get_info')); 81 | 82 | $this->mock->getInfoSharedRosterGroup('groupId'); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /tests/GameNet/Jabber/RoomTest.php: -------------------------------------------------------------------------------- 1 | 9 | * @version 1.0 10 | */ 11 | class RoomTest extends PHPUnit_Framework_TestCase 12 | { 13 | private $mock; 14 | 15 | public function setUp() 16 | { 17 | $this->mock = $this->getMockBuilder('\GameNet\Jabber\RpcClient') 18 | ->disableOriginalConstructor() 19 | ->setMethods(['sendRequest']) 20 | ->getMock(); 21 | } 22 | 23 | public function testCreateRoom() 24 | { 25 | $this->mock->expects($this->once()) 26 | ->method('sendRequest') 27 | ->with($this->equalTo('create_room')); 28 | 29 | $this->mock->createRoom('name'); 30 | } 31 | 32 | public function testInviteToRoom() 33 | { 34 | $this->mock->expects($this->once()) 35 | ->method('sendRequest') 36 | ->with($this->equalTo('send_direct_invitation')); 37 | 38 | $this->mock->inviteToRoom('name', 'password', 'reason', ['contact']); 39 | } 40 | 41 | public function testDeleteRoom() 42 | { 43 | $this->mock->expects($this->once()) 44 | ->method('sendRequest') 45 | ->with($this->equalTo('destroy_room')); 46 | 47 | $this->mock->deleteRoom('name'); 48 | } 49 | 50 | public function testGetOnlineRooms() 51 | { 52 | $this->mock->expects($this->once()) 53 | ->method('sendRequest') 54 | ->with($this->equalTo('muc_online_rooms')); 55 | 56 | $this->mock->getOnlineRooms('name'); 57 | } 58 | 59 | public function testSetRoomOption() 60 | { 61 | $this->mock->expects($this->once()) 62 | ->method('sendRequest') 63 | ->with($this->equalTo('change_room_option')); 64 | 65 | $this->mock->setRoomOption('name', 'option', 'value'); 66 | } 67 | 68 | public function testSetRoomAffiliation() 69 | { 70 | $this->mock->expects($this->once()) 71 | ->method('sendRequest') 72 | ->with($this->equalTo('set_room_affiliation')); 73 | 74 | $this->mock->setRoomAffiliation('name', 'option', 'value'); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tests/GameNet/Jabber/RosterTest.php: -------------------------------------------------------------------------------- 1 | 9 | * @version 1.0 10 | */ 11 | class RosterTest extends PHPUnit_Framework_TestCase 12 | { 13 | private $mock; 14 | 15 | public function setUp() 16 | { 17 | $this->mock = $this->getMockBuilder('\GameNet\Jabber\RpcClient') 18 | ->disableOriginalConstructor() 19 | ->setMethods(['sendRequest']) 20 | ->getMock(); 21 | } 22 | 23 | public function testGetRoster() 24 | { 25 | $this->mock->expects($this->once()) 26 | ->method('sendRequest') 27 | ->with($this->equalTo('get_roster')); 28 | 29 | $this->mock->getRoster('user'); 30 | } 31 | 32 | public function testAddRosterItem() 33 | { 34 | $this->mock->expects($this->once()) 35 | ->method('sendRequest') 36 | ->with($this->equalTo('add_rosteritem')); 37 | 38 | $this->mock->addRosterItem('user', 'contact', 'nickname'); 39 | } 40 | 41 | public function testRemoveRosterItem() 42 | { 43 | $this->mock->expects($this->once()) 44 | ->method('sendRequest') 45 | ->with($this->equalTo('delete_rosteritem')); 46 | 47 | $this->mock->deleteRosterItem('user', 'contact'); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/GameNet/Jabber/RpcClientTest.php: -------------------------------------------------------------------------------- 1 | 11 | * @version 1.0 12 | */ 13 | class RpcClientTest extends PHPUnit_Framework_TestCase 14 | { 15 | /** 16 | * @dataProvider invalidTimeoutValues 17 | * @expectedException \InvalidArgumentException 18 | */ 19 | public function testInvalidTimeoutValue($value) 20 | { 21 | $this->getClient()->setTimeout($value); 22 | } 23 | 24 | public function invalidTimeoutValues() 25 | { 26 | return [ 27 | ['1'], 28 | [-1], 29 | [[]], 30 | ]; 31 | } 32 | 33 | public function testSetGetTimeout() 34 | { 35 | $client = $this->getClient(); 36 | $client->setTimeout(600); 37 | $this->assertEquals(600, $client->getTimeout()); 38 | } 39 | 40 | /** 41 | * @dataProvider invalidCredentials 42 | * @expectedException InvalidArgumentException 43 | */ 44 | public function testInvalidCredentials($username, $password) 45 | { 46 | $this->getClient(['username' => $username, 'password' => $password]); 47 | } 48 | 49 | public function invalidCredentials() 50 | { 51 | return [ 52 | ['username' => 'username', 'password' => ''], 53 | ['username' => '', 'password' => 'password'], 54 | ]; 55 | } 56 | 57 | private function getClient(array $options = []) 58 | { 59 | return new RpcClient(['server' => 'test', 'host' => 'test'] + $options); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/GameNet/Jabber/UserTest.php: -------------------------------------------------------------------------------- 1 | 9 | * @version 1.0 10 | */ 11 | class UserTest extends PHPUnit_Framework_TestCase 12 | { 13 | private $mock; 14 | 15 | public function setUp() 16 | { 17 | $this->mock = $this->getMockBuilder('\GameNet\Jabber\RpcClient') 18 | ->disableOriginalConstructor() 19 | ->setMethods(['sendRequest']) 20 | ->getMock(); 21 | } 22 | 23 | public function testCreateUser() 24 | { 25 | $this->mock->expects($this->once()) 26 | ->method('sendRequest') 27 | ->with($this->equalTo('register')); 28 | 29 | $this->mock->createUser('user', 'password'); 30 | } 31 | 32 | public function testCheckAccount() 33 | { 34 | $this->mock->expects($this->once()) 35 | ->method('sendRequest') 36 | ->with($this->equalTo('check_account')); 37 | 38 | $this->mock->checkAccount('user'); 39 | } 40 | 41 | public function testChangePassword() 42 | { 43 | $this->mock->expects($this->once()) 44 | ->method('sendRequest') 45 | ->with($this->equalTo('change_password')); 46 | 47 | $this->mock->changePassword('user', 'password'); 48 | } 49 | 50 | public function testSetNickname() 51 | { 52 | $this->mock->expects($this->once()) 53 | ->method('sendRequest') 54 | ->with($this->equalTo('set_nickname')); 55 | 56 | $this->mock->setNickname('user', 'nickname'); 57 | } 58 | 59 | public function testLetLastActivity() 60 | { 61 | $this->mock->expects($this->once()) 62 | ->method('sendRequest') 63 | ->with($this->equalTo('get_last')); 64 | 65 | $this->mock->getLastActivity('user'); 66 | } 67 | 68 | public function testSendMessageChat() 69 | { 70 | $this->mock->expects($this->once()) 71 | ->method('sendRequest') 72 | ->with($this->equalTo('send_message_chat')); 73 | 74 | $this->mock->sendMessageChat('from', 'to', 'body'); 75 | } 76 | 77 | public function testUnregisterUser() 78 | { 79 | $this->mock->expects($this->once()) 80 | ->method('sendRequest') 81 | ->with($this->equalTo('unregister')); 82 | 83 | $this->mock->unregisterUser('user'); 84 | } 85 | 86 | public function testSetStatus() 87 | { 88 | $this->mock->expects($this->once()) 89 | ->method('sendRequest'); 90 | 91 | $this->mock->setStatus('user', 'show', 'status', 'priority'); 92 | } 93 | 94 | public function testUserSessionsInfo() 95 | { 96 | $this->mock->expects($this->once()) 97 | ->method('sendRequest') 98 | ->with($this->equalTo('user_sessions_info')); 99 | 100 | $this->mock->userSessionsInfo('user'); 101 | } 102 | 103 | public function testGetVCard() 104 | { 105 | $this->mock->expects($this->once()) 106 | ->method('sendRequest') 107 | ->with($this->equalTo('get_vcard')); 108 | 109 | $this->mock->getVCard('user', 'name'); 110 | } 111 | 112 | public function testGetVCardExtra() 113 | { 114 | $this->mock->expects($this->once()) 115 | ->method('sendRequest') 116 | ->with($this->equalTo('get_vcard2')); 117 | 118 | $this->mock->getVCard('user', 'extra name'); 119 | } 120 | 121 | public function testSetVCard() 122 | { 123 | $this->mock->expects($this->once()) 124 | ->method('sendRequest') 125 | ->with($this->equalTo('set_vcard')); 126 | 127 | $this->mock->setVCard('user', 'name', 'value'); 128 | } 129 | 130 | public function testSetVCardExtra() 131 | { 132 | $this->mock->expects($this->once()) 133 | ->method('sendRequest') 134 | ->with($this->equalTo('set_vcard2')); 135 | 136 | $this->mock->setVCard('user', 'extra name', 'value'); 137 | } 138 | 139 | public function testBanAccount() 140 | { 141 | $this->mock->expects($this->once()) 142 | ->method('sendRequest') 143 | ->with($this->equalTo('ban_account')); 144 | 145 | $this->mock->banAccount('user', 'reason'); 146 | } 147 | 148 | public function testSetGroupForUserRoster() 149 | { 150 | $this->mock->expects($this->once()) 151 | ->method('sendRequest'); 152 | 153 | $this->mock->setGroupForUserRoster('user', 'contact', ['group']); 154 | } 155 | 156 | public function testSendStanza() 157 | { 158 | $this->mock->expects($this->once()) 159 | ->method('sendRequest'); 160 | 161 | $this->mock->sendStanzaC2S('user', 'stanza'); 162 | } 163 | 164 | public function testAddUserToGroup() 165 | { 166 | $this->mock->expects($this->once()) 167 | ->method('sendRequest'); 168 | 169 | $this->mock->addUserToGroup('user', 'contact', 'group'); 170 | } 171 | 172 | public function testDeleteUserFromGroup() 173 | { 174 | $this->mock->expects($this->once()) 175 | ->method('sendRequest'); 176 | 177 | $this->mock->deleteUserFromGroup('user', 'contact', 'group'); 178 | } 179 | 180 | public function testGetConnectedUsers() 181 | { 182 | $this->mock->expects($this->once()) 183 | ->method('sendRequest'); 184 | 185 | $this->mock->getConnectedUsers(); 186 | } 187 | } 188 | --------------------------------------------------------------------------------