mantis-matrix-integration – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 <?php
2  
3 namespace MatrixPhp;
4  
5 use MatrixPhp\Exceptions\MatrixRequestException;
6 use function GuzzleHttp\default_ca_bundle;
7 use http\Exception;
8 use phpDocumentor\Reflection\DocBlock\Tags\Param;
9  
10 /**
11 * Call room-specific functions after joining a room from the client.
12 *
13 * NOTE: This should ideally be called from within the Client.
14 * NOTE: This does not verify the room with the Home Server.
15 *
16 * @package MatrixPhp
17 */
18 class Room {
19  
20 /** @var MatrixClient */
21 protected $client;
22 protected $roomId;
23 protected $listeners = [];
24 protected $stateListeners = [];
25 protected $ephemeralListeners = [];
26 protected $events = [];
27 protected $eventHistoryLimit = 20;
28 protected $name;
29 protected $canonicalAlias;
30 protected $aliases = [];
31 protected $topic;
32 protected $inviteOnly = false;
33 protected $guestAccess;
34 public $prevBatch;
35 protected $_members = [];
36 protected $membersDisplaynames = [
37 // $userId: $displayname,
38 ];
39 protected $encrypted = false;
40  
41 public function __construct(MatrixClient $client, string $roomId) {
42 Util::checkRoomId($roomId);
43 $this->roomId = $roomId;
44 $this->client = $client;
45 }
46  
47 /**
48 * Set user profile within a room.
49 *
50 * This sets displayname and avatar_url for the logged in user only in a
51 * specific room. It does not change the user's global user profile.
52 *
53 * @param string|null $displayname
54 * @param string|null $avatarUrl
55 * @param string $reason
56 * @throws Exceptions\MatrixException
57 * @throws Exceptions\MatrixHttpLibException
58 * @throws Exceptions\MatrixRequestException
59 */
60 public function setUserProfile(?string $displayname = null, ?string $avatarUrl = null,
61 string $reason = "Changing room profile information") {
62 $member = $this->api()->getMembership($this->roomId, $this->client->userId());
63 if ($member['membership'] != 'join') {
64 throw new \Exception("Can't set profile if you have not joined the room.");
65 }
66 if (!$displayname) {
67 $displayname = $member["displayname"];
68 }
69 if (!$avatarUrl) {
70 $avatarUrl = $member["avatar_url"];
71 }
72 $this->api()->setMembership(
73 $this->roomId,
74 $this->client->userId(),
75 'join',
76 $reason,
77 [
78 "displayname" => $displayname,
79 "avatar_url" => $avatarUrl
80 ]
81 );
82 }
83  
84 /**
85 * Calculates the display name for a room.
86 *
87 * @return string
88 */
89 public function displayName() {
90 if ($this->name) {
91 return $this->name;
92 } elseif ($this->canonicalAlias) {
93 return $this->canonicalAlias;
94 }
95  
96 // Member display names without me
97 $members = array_reduce($this->getJoinedMembers(), function (array $all, User $u) {
98 if ($this->client->userId() != $u->userId()) {
99 $all[] = $u->getDisplayName($this);
100 }
101 return $all;
102 }, []);
103 sort($members);
104  
105 switch (count($members)) {
106 case 0:
107 return 'Empty room';
108 case 1:
109 return $members[0];
110 case 2:
111 return sprintf("%s and %s", $members[0], $members[1]);
112 default:
113 return sprintf("%s and %d others.", $members[0], count($members));
114 }
115 }
116  
117 /**
118 * Send a plain text message to the room.
119 *
120 * @param string $text
121 * @return array|string
122 * @throws Exceptions\MatrixException
123 * @throws Exceptions\MatrixHttpLibException
124 * @throws Exceptions\MatrixRequestException
125 */
126 public function sendText(string $text) {
127 return $this->api()->sendMessage($this->roomId, $text);
128 }
129  
130 public function getHtmlContent(string $html, ?string $body = null, string $msgType = 'm.text') {
131 return [
132 'body' => $body ?: strip_tags($html),
133 'msgtype' => $msgType,
134 'format' => "org.matrix.custom.html",
135 'formatted_body' => $html,
136 ];
137 }
138  
139 /**
140 * Send an html formatted message.
141 *
142 * @param string $html The html formatted message to be sent.
143 * @param string|null $body The unformatted body of the message to be sent.
144 * @param string $msgType
145 * @return array|string
146 * @throws Exceptions\MatrixException
147 * @throws Exceptions\MatrixHttpLibException
148 * @throws Exceptions\MatrixRequestException
149 */
150 public function sendHtml(string $html, ?string $body = null, string $msgType = 'm.text') {
151 $content = $this->getHtmlContent($html, $body, $msgType);
152  
153 return $this->api()->sendMessageEvent($this->roomId, 'm.room.message', $content);
154 }
155  
156 /**
157 * @param string $type
158 * @param array $data
159 * @return array|string
160 * @throws Exceptions\MatrixException
161 * @throws Exceptions\MatrixHttpLibException
162 * @throws Exceptions\MatrixRequestException
163 */
164 public function setAccountData(string $type, array $data) {
165 return $this->api()->setRoomAccountData($this->client->userId(), $this->roomId, $type, $data);
166 }
167  
168 /**
169 * @return array|string
170 * @throws Exceptions\MatrixException
171 * @throws Exceptions\MatrixHttpLibException
172 * @throws Exceptions\MatrixRequestException
173 */
174 public function getTags() {
175 return $this->api()->getUserTags($this->client->userId(), $this->roomId);
176 }
177  
178 /**
179 * @param string $tag
180 * @return array|string
181 * @throws Exceptions\MatrixException
182 * @throws Exceptions\MatrixHttpLibException
183 * @throws Exceptions\MatrixRequestException
184 */
185 public function removeTag(string $tag) {
186 return $this->api()->removeUserTag($this->client->userId(), $this->roomId, $tag);
187 }
188  
189 /**
190 * @param string $tag
191 * @param float|null $order
192 * @param array $content
193 * @return array|string
194 * @throws Exceptions\MatrixException
195 * @throws Exceptions\MatrixHttpLibException
196 * @throws Exceptions\MatrixRequestException
197 */
198 public function addTag(string $tag, ?float $order = null, array $content = []) {
199 return $this->api()->addUserTag($this->client->userId(), $this->roomId, $tag, $order, $content);
200 }
201  
202 /**
203 * Send an emote (/me style) message to the room.
204 *
205 * @param string $text
206 * @return array|string
207 * @throws Exceptions\MatrixException
208 * @throws Exceptions\MatrixHttpLibException
209 * @throws Exceptions\MatrixRequestException
210 */
211 public function sendEmote(string $text) {
212 return $this->api()->sendEmote($this->roomId, $text);
213 }
214  
215 /**
216 * Send a pre-uploaded file to the room.
217 *
218 * See http://matrix.org/docs/spec/r0.4.0/client_server.html#m-file for fileinfo.
219 *
220 * @param string $url The mxc url of the file.
221 * @param string $name The filename of the image.
222 * @param array $fileinfo Extra information about the file
223 * @return array|string
224 * @throws Exceptions\MatrixException
225 * @throws Exceptions\MatrixHttpLibException
226 * @throws Exceptions\MatrixRequestException
227 */
228 public function sendFile(string $url, string $name, array $fileinfo) {
229 return $this->api()->sendContent($this->roomId, $url, $name, 'm.file', $fileinfo);
230 }
231  
232 /**
233 * Send a notice (from bot) message to the room.
234 *
235 * @param string $text
236 * @return array|string
237 * @throws Exceptions\MatrixException
238 * @throws Exceptions\MatrixHttpLibException
239 * @throws Exceptions\MatrixRequestException
240 */
241 public function sendNotice(string $text) {
242 return $this->api()->sendNotice($this->roomId, $text);
243 }
244  
245 /**
246 * Send a pre-uploaded image to the room.
247 *
248 * See http://matrix.org/docs/spec/r0.0.1/client_server.html#m-image for imageinfo
249 *
250 * @param string $url The mxc url of the image.
251 * @param string $name The filename of the image.
252 * @param array $fileinfo Extra information about the image.
253 * @return array|string
254 * @throws Exceptions\MatrixException
255 * @throws Exceptions\MatrixHttpLibException
256 * @throws Exceptions\MatrixRequestException
257 */
258 public function sendImage(string $url, string $name, ?array $fileinfo) {
259 return $this->api()->sendContent($this->roomId, $url, $name, 'm.image', $fileinfo);
260 }
261  
262 /**
263 * Send a location to the room.
264 * See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-location for thumb_info
265 *
266 * @param string $geoUri The geo uri representing the location.
267 * @param string $name Description for the location.
268 * @param array $thumbInfo Metadata about the thumbnail, type ImageInfo.
269 * @param string|null $thumbUrl URL to the thumbnail of the location.
270 * @return array|string
271 * @throws Exceptions\MatrixException
272 * @throws Exceptions\MatrixHttpLibException
273 * @throws Exceptions\MatrixRequestException
274 */
275 public function sendLocation(string $geoUri, string $name, ?array $thumbInfo, ?string $thumbUrl = null) {
276 return $this->api()->sendLocation($this->roomId, $geoUri, $name, $thumbUrl, $thumbInfo);
277 }
278  
279 /**
280 * Send a pre-uploaded video to the room.
281 * See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-video for videoinfo
282 *
283 * @param string $url The mxc url of the video.
284 * @param string $name The filename of the video.
285 * @param array $videoinfo Extra information about the video.
286 * @return array|string
287 * @throws Exceptions\MatrixException
288 * @throws Exceptions\MatrixHttpLibException
289 * @throws Exceptions\MatrixRequestException
290 */
291 public function sendVideo(string $url, string $name, ?array $videoinfo) {
292 return $this->api()->sendContent($this->roomId, $url, $name, 'm.video', $videoinfo);
293 }
294  
295 /**
296 * Send a pre-uploaded audio to the room.
297 * See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-audio for audioinfo
298 *
299 * @param string $url The mxc url of the video.
300 * @param string $name The filename of the video.
301 * @param array $audioinfo Extra information about the video.
302 * @return array|string
303 * @throws Exceptions\MatrixException
304 * @throws Exceptions\MatrixHttpLibException
305 * @throws Exceptions\MatrixRequestException
306 */
307 public function sendAudio(string $url, string $name, ?array $audioinfo) {
308 return $this->api()->sendContent($this->roomId, $url, $name, 'm.audio', $audioinfo);
309 }
310  
311 /**
312 * Redacts the message with specified event_id for the given reason.
313 *
314 * See https://matrix.org/docs/spec/r0.0.1/client_server.html#id112
315 *
316 * @param string $eventId
317 * @param string|null $reason
318 * @return array|string
319 * @throws Exceptions\MatrixException
320 * @throws Exceptions\MatrixHttpLibException
321 * @throws Exceptions\MatrixRequestException
322 */
323 public function redactMessage(string $eventId, ?string $reason = null) {
324 return $this->api()->redactEvent($this->roomId, $eventId, $reason);
325 }
326  
327 /**
328 * Add a callback handler for events going to this room.
329 *
330 * @param callable $cb (func(room, event)): Callback called when an event arrives.
331 * @param string|null $eventType The event_type to filter for.
332 * @return string Unique id of the listener, can be used to identify the listener.
333 */
334 public function addListener(callable $cb, ?string $eventType = null) {
335 $listenerId = uniqid();
336 $this->listeners[] = [
337 'uid' => $listenerId,
338 'callback' => $cb,
339 'event_type' => $eventType,
340 ];
341  
342 return $listenerId;
343 }
344  
345 /**
346 * Remove listener with given uid.
347 *
348 * @param string $uid
349 */
350 public function removeListener(string $uid) {
351 $this->listeners = array_filter($this->listeners, function ($l) use ($uid) {
352 return $l['uid'] != $uid;
353 });
354 }
355  
356 /**
357 * Add a callback handler for ephemeral events going to this room.
358 *
359 * @param callable $cb (func(room, event)): Callback called when an ephemeral event arrives.
360 * @param string|null $eventType The event_type to filter for.
361 * @return string Unique id of the listener, can be used to identify the listener.
362 */
363 public function addEphemeralListener(callable $cb, ?string $eventType = null) {
364 $listenerId = uniqid();
365 $this->ephemeralListeners[] = [
366 'uid' => $listenerId,
367 'callback' => $cb,
368 'event_type' => $eventType,
369 ];
370  
371 return $listenerId;
372 }
373  
374 /**
375 * Remove ephemeral listener with given uid.
376 *
377 * @param string $uid
378 */
379 public function removeEphemeralListener(string $uid) {
380 $this->ephemeralListeners = array_filter($this->ephemeralListeners, function ($l) use ($uid) {
381 return $l['uid'] != $uid;
382 });
383 }
384  
385 /**
386 * Add a callback handler for state events going to this room.
387 *
388 * @param callable $cb Callback called when an event arrives.
389 * @param string|null $eventType The event_type to filter for.
390 */
391 public function addStateListener(callable $cb, ?string $eventType = null) {
392 $this->stateListeners[] = [
393 'callback' => $cb,
394 'event_type' => $eventType,
395 ];
396 }
397  
398 public function putEvent(array $event) {
399 $this->events[] = $event;
400 if (count($this->events) > $this->eventHistoryLimit) {
401 array_pop($this->events);
402 }
403 if (array_key_exists('state_event', $event)) {
404 $this->processStateEvent($event);
405 }
406 // Dispatch for room-specific listeners
407 foreach ($this->listeners as $l) {
408 if (!$l['event_type'] || $l['event_type'] == $event['event_type']) {
409 $l['cb']($this, $event);
410 }
411 }
412 }
413  
414 public function putEphemeralEvent(array $event) {
415 // Dispatch for room-specific listeners
416 foreach ($this->ephemeralListeners as $l) {
417 if (!$l['event_type'] || $l['event_type'] == $event['event_type']) {
418 $l['cb']($this, $event);
419 }
420 }
421 }
422  
423 /**
424 * Get the most recent events for this room.
425 *
426 * @return array
427 */
428 public function getEvents(): array {
429 return $this->events;
430 }
431  
432 /**
433 * Invite a user to this room.
434 *
435 * @param string $userId
436 * @return bool Whether invitation was sent.
437 * @throws Exceptions\MatrixException
438 * @throws Exceptions\MatrixHttpLibException
439 */
440 public function inviteUser(string $userId): bool {
441 try {
442 $this->api()->inviteUser($this->roomId, $userId);
443 } catch (MatrixRequestException $e) {
444 return false;
445 }
446  
447 return true;
448 }
449  
450 /**
451 * Kick a user from this room.
452 *
453 * @param string $userId The matrix user id of a user.
454 * @param string $reason A reason for kicking the user.
455 * @return bool Whether user was kicked.
456 * @throws Exceptions\MatrixException
457 */
458 public function kickUser(string $userId, string $reason = ''): bool {
459 try {
460 $this->api()->kickUser($this->roomId, $userId, $reason);
461 } catch (MatrixRequestException $e) {
462 return false;
463 }
464  
465 return true;
466 }
467  
468 /**
469 * Ban a user from this room.
470 *
471 * @param string $userId The matrix user id of a user.
472 * @param string $reason A reason for banning the user.
473 * @return bool Whether user was banned.
474 * @throws Exceptions\MatrixException
475 */
476 public function banUser(string $userId, string $reason = ''): bool {
477 try {
478 $this->api()->banUser($this->roomId, $userId, $reason);
479 } catch (MatrixRequestException $e) {
480 return false;
481 }
482  
483 return true;
484 }
485  
486 /**
487 * Leave the room.
488 *
489 * @return bool Leaving the room was successful.
490 * @throws Exceptions\MatrixException
491 * @throws Exceptions\MatrixHttpLibException
492 */
493 public function leave() {
494 try {
495 $this->api()->leaveRoom($this->roomId);
496 // @todo This is not implemented from the original library?
497 // $this->client->forgetRoom($this->roomId);
498 } catch (MatrixRequestException $e) {
499 return false;
500 }
501  
502 return true;
503 }
504  
505 /**
506 * Updates $this->name and returns true if room name has changed.
507 * @return bool
508 * @throws Exceptions\MatrixException
509 */
510 public function updateRoomName() {
511 try {
512 $response = $this->api()->getRoomName($this->roomId);
513 $newName = array_get($response, 'name', $this->name);
514 $this->name = $newName;
515 if ($this->name != $newName) {
516 $this->name = $newName;
517 return true;
518 }
519 } catch (MatrixRequestException $e) {
520 }
521  
522 return false;
523 }
524  
525 /**
526 * Return True if room name successfully changed.
527 *
528 * @param string $name
529 * @return bool
530 * @throws Exceptions\MatrixException
531 */
532 public function setRoomName(string $name) {
533 try {
534 $this->api()->setRoomName($this->roomId, $name);
535 $this->name = $name;
536 } catch (MatrixRequestException $e) {
537 return false;
538 }
539  
540 return true;
541 }
542  
543 /**
544 * Send a state event to the room.
545 *
546 * @param string $eventType The type of event that you are sending.
547 * @param array $content An object with the content of the message.
548 * @param string $stateKey Optional. A unique key to identify the state.
549 * @throws Exceptions\MatrixException
550 */
551 public function sendStateEvent(string $eventType, array $content, string $stateKey = '') {
552 $this->api()->sendStateEvent($this->roomId, $eventType, $content, $stateKey);
553 }
554  
555 /**
556 * Updates $this->topic and returns true if room topic has changed.
557 *
558 * @return bool
559 * @throws Exceptions\MatrixException
560 */
561 public function updateRoomTopic() {
562 try {
563 $response = $this->api()->getRoomTopic($this->roomId);
564 $oldTopic = $this->topic;
565 $this->topic = array_get($response, 'topic', $this->topic);
566 } catch (MatrixRequestException $e) {
567 return false;
568 }
569  
570 return $oldTopic == $this->topic;
571 }
572  
573 /**
574 * Return True if room topic successfully changed.
575 *
576 * @param string $topic
577 * @return bool
578 * @throws Exceptions\MatrixException
579 */
580 public function setRoomTopic(string $topic) {
581 try {
582 $this->api()->setRoomTopic($this->roomId, $topic);
583 $this->topic = $topic;
584 } catch (MatrixRequestException $e) {
585 return false;
586 }
587  
588 return true;
589 }
590  
591 /**
592 * Get aliases information from room state.
593 *
594 * @return bool True if the aliases changed, False if not
595 * @throws Exceptions\MatrixException
596 * @throws Exceptions\MatrixHttpLibException
597 */
598 public function updateAliases() {
599 try {
600 $response = $this->api()->getRoomState($this->roomId);
601 $oldAliases = $this->aliases;
602 foreach ($response as $chunk) {
603 if ($aliases = array_get($chunk, 'content.aliases')) {
604 $this->aliases = $aliases;
605 }
606 }
607 } catch (MatrixRequestException $e) {
608 return false;
609 }
610 // @todo Validate this logic.
611 return $this->aliases !== $oldAliases;
612 }
613  
614 /**
615 * Add an alias to the room and return True if successful.
616 *
617 * @param string $alias
618 * @return bool
619 * @throws Exceptions\MatrixException
620 * @throws Exceptions\MatrixHttpLibException
621 */
622 public function addRoomAlias(string $alias) {
623 try {
624 $this->api()->setRoomAlias($this->roomId, $alias);
625 } catch (MatrixRequestException $e) {
626 return false;
627 }
628  
629 return true;
630 }
631  
632 public function getJoinedMembers() {
633 if ($this->_members) {
634 return array_values($this->_members);
635 }
636 $response = $this->api()->getRoomMembers($this->roomId);
637 foreach ($response['chunk'] as $event) {
638 if (array_get($event, 'event.membership') == 'join') {
639 $userId = $event['state_key'];
640 $this->addMember($userId, array_get($event, 'content.displayname'));
641 }
642 }
643  
644 return array_values($this->_members);
645 }
646  
647 protected function addMember(string $userId, ?string $displayname) {
648 if ($displayname) {
649 $this->membersDisplaynames[$userId] = $displayname;
650 }
651 if (array_key_exists($userId, $this->_members)) {
652 return;
653 }
654 if (array_key_exists($userId, $this->client->users)) {
655 $this->_members[$userId] = $this->client->users[$userId];
656 return;
657 }
658 $this->_members[$userId] = new User($this->api(), $userId, $displayname);
659 $this->client->users[$userId] = $this->_members[$userId];
660 }
661  
662 /**
663 * Backfill handling of previous messages.
664 *
665 * @param bool $reverse When false messages will be backfilled in their original
666 * order (old to new), otherwise the order will be reversed (new to old).
667 * @param int $limit Number of messages to go back.
668 * @throws Exceptions\MatrixException
669 * @throws Exceptions\MatrixHttpLibException
670 * @throws MatrixRequestException
671 */
672 public function backfillPreviousMessages(bool $reverse = false, int $limit = 10) {
673 $res = $this->api()->getRoomMessages($this->roomId, $this->prevBatch, 'b', $limit);
674 $events = $res['chunk'];
675 if (!$reverse) {
676 $events = array_reverse($events);
677 }
678 foreach ($events as $event) {
679 $this->putEvent($event);
680 }
681 }
682  
683 /**
684 * Modify the power level for a subset of users
685 *
686 * @param array $users Power levels to assign to specific users, in the form
687 * {"@name0:host0": 10, "@name1:host1": 100, "@name3:host3", None}
688 * A level of None causes the user to revert to the default level
689 * as specified by users_default.
690 * @param int $userDefault Default power level for users in the room
691 * @return bool
692 * @throws Exceptions\MatrixException
693 */
694 public function modifyUserPowerLevels(array $users = null, int $userDefault = null) {
695 try {
696 $content = $this->api()->getPowerLevels($this->roomId);
697 if ($userDefault) {
698 $content['user_default'] = $userDefault;
699 }
700  
701 if ($users) {
702 if (array_key_exists('users', $content)) {
703 $content['users'] = array_merge($content['users'], $content);
704 } else {
705 $content['users'] = $users;
706 }
707  
708 // Remove any keys with value null
709 foreach ($content['users'] as $user => $pl) {
710 if (!$pl) {
711 unset($content['users'][$user]);
712 }
713 }
714 }
715  
716 $this->api()->setPowerLevels($this->roomId, $content);
717 } catch (MatrixRequestException $e) {
718 return false;
719 }
720  
721 return true;
722 }
723  
724 /**
725 * Modifies room power level requirements.
726 *
727 * @param array $events Power levels required for sending specific event types,
728 * in the form {"m.room.whatever0": 60, "m.room.whatever2": None}.
729 * Overrides events_default and state_default for the specified
730 * events. A level of None causes the target event to revert to the
731 * default level as specified by events_default or state_default.
732 * @param array $extra Key/value pairs specifying the power levels required for
733 * various actions:
734 *
735 * - events_default(int): Default level for sending message events
736 * - state_default(int): Default level for sending state events
737 * - invite(int): Inviting a user
738 * - redact(int): Redacting an event
739 * - ban(int): Banning a user
740 * - kick(int): Kicking a user
741 * @return bool
742 * @throws Exceptions\MatrixException
743 */
744 public function modifyRequiredPowerLevels(array $events = [], array $extra = []) {
745 try {
746 $content = $this->api()->getPowerLevels($this->roomId);
747 $content = array_merge($content, $extra);
748 foreach ($content as $k => $v) {
749 if (!$v) {
750 unset($content[$k]);
751 }
752 }
753  
754 if ($events) {
755 if (array_key_exists('events', $content)) {
756 $content["events"] = array_merge($content["events"], $events);
757 } else {
758 $content["events"] = $events;
759 }
760  
761 // Remove any keys with value null
762 foreach ($content['event'] as $event => $pl) {
763 if (!$pl) {
764 unset($content['event'][$event]);
765 }
766 }
767 }
768  
769 $this->api()->setPowerLevels($this->roomId, $content);
770 } catch (MatrixRequestException $e) {
771 return false;
772 }
773  
774 return true;
775 }
776  
777 /**
778 * Set how the room can be joined.
779 *
780 * @param bool $inviteOnly If True, users will have to be invited to join
781 * the room. If False, anyone who knows the room link can join.
782 * @return bool True if successful, False if not
783 * @throws Exceptions\MatrixException
784 */
785 public function setInviteOnly(bool $inviteOnly) {
786 $joinRule = $inviteOnly ? 'invite' : 'public';
787 try {
788 $this->api()->setJoinRule($this->roomId, $joinRule);
789 $this->inviteOnly = $inviteOnly;
790 } catch (MatrixRequestException $e) {
791 return false;
792 }
793  
794 return true;
795 }
796  
797 /**
798 * Set whether guests can join the room and return True if successful.
799 *
800 * @param bool $allowGuest
801 * @return bool
802 * @throws Exceptions\MatrixException
803 */
804 public function setGuestAccess(bool $allowGuest) {
805 $guestAccess = $allowGuest ? 'can_join' : 'forbidden';
806 try {
807 $this->api()->setGuestAccess($this->roomId, $guestAccess);
808 $this->guestAccess = $allowGuest;
809 } catch (MatrixRequestException $e) {
810 return false;
811 }
812  
813 return true;
814 }
815  
816 /**
817 * Enables encryption in the room.
818 *
819 * NOTE: Once enabled, encryption cannot be disabled.
820 *
821 * @return bool True if successful, False if not
822 * @throws Exceptions\MatrixException
823 */
824 public function enableEncryption() {
825 try {
826 $this->sendStateEvent('m.room.encryption', ['algorithm' => 'm.megolm.v1.aes-sha2']);
827 $this->encrypted = true;
828 } catch (MatrixRequestException $e) {
829 return false;
830 }
831  
832 return true;
833 }
834  
835 public function processStateEvent(array $stateEvent) {
836 if (!array_key_exists('type', $stateEvent)) {
837 return;
838 }
839 $etype = $stateEvent['type'];
840 $econtent = $stateEvent['content'];
841 $clevel = $this->client->cacheLevel();
842  
843 // Don't keep track of room state if caching turned off
844 if ($clevel >= Cache::SOME) {
845 switch ($etype) {
846 case 'm.room.name':
847 $this->name = array_get($econtent, 'name');
848 break;
849 case 'm.room.canonical_alias':
850 $this->canonicalAlias = array_get($econtent, 'alias');
851 break;
852 case 'm.room.topic':
853 $this->topic = array_get($econtent, 'topic');
854 break;
855 case 'm.room.aliases':
856 $this->aliases = array_get($econtent, 'aliases');
857 break;
858 case 'm.room.join_rules':
859 $this->inviteOnly = $econtent["join_rule"] == "invite";
860 break;
861 case 'm.room.guest_access':
862 $this->guestAccess = $econtent["guest_access"] == "can_join";
863 break;
864 case 'm.room.encryption':
865 $this->encrypted = array_get($econtent, 'algorithm') ? true : $this->encrypted;
866 break;
867 case 'm.room.member':
868 // tracking room members can be large e.g. #matrix:matrix.org
869 if ($clevel == Cache::ALL) {
870 if ($econtent['membership'] == 'join') {
871 $userId = $stateEvent['state_key'];
872 $this->addMember($userId, array_get($econtent, 'displayname'));
873 } elseif (in_array($econtent["membership"], ["leave", "kick", "invite"])) {
874 unset($this->_members[array_get($stateEvent, 'state_key')]);
875 }
876 }
877 break;
878 }
879 }
880  
881 foreach ($this->stateListeners as $listener) {
882 if (!$listener['event_type'] || $listener['event_type'] == $stateEvent['type']) {
883 $listener['cb']($stateEvent);
884 }
885 }
886 }
887  
888 public function getMembersDisplayNames(): array {
889 return $this->membersDisplaynames;
890 }
891  
892 protected function api(): MatrixHttpApi {
893 return $this->client->api();
894 }
895  
896  
897 }