You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

433 lines
13 KiB

<?php
namespace App\Widgets\Rooms;
use Moxl\Xec\Action\Disco\Request;
use Moxl\Xec\Action\Presence\Muc;
use Moxl\Xec\Action\Presence\Unavailable;
use Moxl\Xec\Action\Muc\GetMembers;
use Movim\Session;
use Movim\ChatStates;
use Movim\Widget\Base;
use App\Conference;
use App\Widgets\Notif\Notif;
use App\Widgets\Toast\Toast;
use Movim\ChatroomPings;
use Movim\CurrentCall;
use Moxl\Xec\Payload\Packet;
class Rooms extends Base
{
public function load()
{
$this->addcss('rooms.css');
$this->addjs('rooms.js');
$this->registerEvent('bookmark2_get_handle', 'onBookmarkGet');
$this->registerEvent('bookmark2', 'onBookmarkSet');
$this->registerEvent('bookmark2_set_handle', 'onBookmarkSet');
$this->registerEvent('bookmark2_delete_handle', 'onBookmarkSet');
$this->registerEvent('muc_destroy_handle', 'onDestroyed', 'chat');
$this->registerEvent('chatstate', 'onChatState', 'chat');
$this->registerEvent('message', 'onMessage');
$this->registerEvent('displayed', 'onDisplayed', 'chat');
$this->registerEvent('presence_unavailable_handle', 'onDisconnected', 'chat');
$this->registerEvent('presence_muc_handle', 'onConnected'/*, 'chat'*/);
$this->registerEvent('presence_muc_errorconflict', 'onConflict');
$this->registerEvent('presence_muc_errorregistrationrequired', 'onRegistrationRequired');
$this->registerEvent('presence_muc_errorremoteservernotfound', 'onRemoteServerNotFound');
$this->registerEvent('presence_muc_errorremoteservertimeout', 'onRemoteServerTimeout');
$this->registerEvent('presence_muc_erroritemnotfound', 'onItemNotFound');
$this->registerEvent('presence_muc_errornotauthorized', 'onNotAuthorized');
$this->registerEvent('presence_muc_errorforbidden', 'onForbidden');
$this->registerEvent('presence_muc_errorjidmalformed', 'onJidMalformed');
$this->registerEvent('presence_muc_errornotacceptable', 'onNotAcceptable');
$this->registerEvent('presence_muc_errorserviceunavailable', 'onServiceUnavailable');
$this->registerEvent('callinvitepropose', 'onCallInvitePropose');
$this->registerEvent('callinviteaccept', 'onCallInvite');
$this->registerEvent('callinviteleft', 'onCallInvite');
$this->registerEvent('callinviteretract', 'onCallInvite');
$this->registerEvent('presence_muji_event', 'onCallInvite');
// Bug: In Chat::ajaxGet, Notif.current might come after this event
// so we don't set the filter
$this->registerEvent('chat_open_room', 'onChatOpen'/*, 'chat'*/);
}
public function onChatOpen(string $room)
{
$this->setCounter($room);
}
public function onChatState(array $array)
{
$this->setState($array[0], isset($array[1]));
}
public function onCallInvitePropose(Packet $packet)
{
$muji = $packet->content;
if ($muji->jidfrom && $muji->conference && !$muji->inviter->me) {
Notif::append(
'chat|' . $muji->jidfrom,
($muji->conference != null && $muji->conference->name)
? $muji->conference->name
: $muji->jidfrom,
($muji->video)
? "📹 " . __('muji.call_video_invite')
: "📞 " . __('muji.call_audio_invite'),
$muji->conference->getPicture(),
5,
$this->route('chat', [$muji->jidfrom, 'room']),
null,
'Search.chat(\'' . echapJS($muji->jidfrom) . '\', true)'
);
$this->onCallInvite($packet);
}
}
public function onCallInvite(Packet $packet)
{
$muji = $packet->content;
if ($muji->jidfrom && $muji->conference) {
$this->onPresence($muji->jidfrom);
}
}
public function onMessage($packet)
{
$message = $packet->content;
if ($message->isMuc()) {
$chatStates = ChatStates::getInstance();
$chatStates->clearState($message->jidfrom, $message->resource);
$this->onChatState($chatStates->getState($message->jidfrom));
$this->setCounter($message->jidfrom);
}
}
public function onDisplayed($packet)
{
$message = $packet->content;
if ($message->isMuc() && $message->jidto == $this->user->id) {
$this->onPresence($message->jidfrom);
}
}
public function onDestroyed($packet)
{
$this->ajaxHttpGet();
$this->rpc('Chat_ajaxGet');
Toast::send($this->__('chatrooms.destroyed'));
}
public function onConnected($packet)
{
list($presence, $notify) = array_values($packet->content);
$this->onPresence($presence->jid);
}
public function onDisconnected($packet)
{
if ($packet->content) {
$this->onPresence($packet->content);
Toast::send($this->__('chatrooms.disconnected'));
}
}
public function onBookmarkGet($packet)
{
foreach (
$this->user->session->conferences()
->where('bookmarkversion', (int)$packet->content)
->get() as $room
) {
if ($room->autojoin && !$room->connected) {
$this->ajaxJoin($room->conference, $room->nick);
}
}
$this->ajaxHttpGet();
}
public function onBookmarkSet($packet)
{
$conference = $packet->content;
if ($conference && $conference->autojoin) {
$this->ajaxJoin($conference->conference, $conference->nick);
}
Toast::send($this->__('bookmarks.updated'));
if ($conference) {
$this->onPresence($conference->conference);
} else {
$this->rpc('Rooms_ajaxHttpGet');
}
}
private function setState(string $room, bool $composing)
{
$this->rpc(
$composing
? 'MovimUtils.addClass'
: 'MovimUtils.removeClass',
'#' . cleanupId($room . '_rooms_primary'),
'composing'
);
}
private function setCounter(string $room)
{
$conference = $this->user->session
->conferences()
->where('conference', $room)
->withCount('unreads', 'quoted')
->first();
if ($conference) {
$this->rpc(
'MovimTpl.fill',
'#' . cleanupId($room . '_rooms_primary'),
$this->prepareRoomCounter($conference, $conference->getPicture())
);
$unread = ($conference->unreads_count > 0 || $conference->quoted_count > 0);
$this->rpc('Rooms.setUnread', cleanupId($room), $unread);
}
}
public function onPresence(string $room, bool $callSecond = true)
{
$conference = $this->user->session->conferences()
->where('conference', $room)
->with('info', 'contact', 'presence')
->withCount('unreads', 'quoted', 'presences')
->first();
if ($conference) {
$this->rpc('Rooms.setRoom', \cleanupId($conference->conference), $this->prepareConference($conference), $callSecond);
}
}
public function ajaxSecondGet(string $room)
{
$this->onPresence($room, callSecond: false);
}
public function ajaxHttpGet()
{
$conferences = $this->user->session->conferences()
->with('info', 'contact', 'presence')
->withCount('unreads', 'quoted', 'presences')
->get();
$this->rpc('Rooms.clearRooms');
foreach ($conferences as $conference) {
$this->rpc('Rooms.setRoom', \cleanupId($conference->conference), $this->prepareConference($conference), true);
}
$this->rpc('Rooms.refresh');
$this->rpc('Rooms.checkNoConnected');
$this->rpc('MovimUtils.removeClass', '#rooms_widget ul.list.rooms', 'spin');
$view = $this->tpl();
$this->rpc('MovimTpl.remove', '#rooms_widget ul.list.empty');
$this->rpc('MovimTpl.appendAfter', '#rooms_widget ul.list.rooms', $view->draw('_rooms_empty'));
}
/**
* @brief Join a chatroom
*/
public function ajaxJoin(string $room, ?string $nickname = null)
{
if (!validateRoom($room)) {
return;
}
$r = new Request;
$r->setTo($room)
->request();
$p = new Muc;
$p->setTo($room);
if ($nickname == null) {
$nickname = $this->user->username;
}
$jid = explodeJid($room);
$capability = \App\Info::where('server', $jid['server'])
->where('node', '')
->first();
if ($capability && ($capability->isMAM() || $capability->isMAM2())) {
$this->rpc('MovimUtils.addClass', '#chat_widget .contained', 'loading');
$p->enableMAM();
if ($capability->isMAM2()) {
$p->enableMAM2();
}
} else {
$r = new Request;
$r->setTo($jid['server'])
->request();
}
$m = new GetMembers;
$m->setTo($room)
->request();
$p->setNickname($nickname);
$p->request();
}
/**
* @brief Exit a room
*
* @param string $room
*/
public function ajaxExit($room)
{
if (!validateRoom($room)) {
return;
}
// We reset the Chat view
$this->rpc('Chat_ajaxGet');
// We properly exit
$conference = $this->user->session->conferences()
->where('conference', $room)
->first();
if (!$conference) return;
$resource = $conference->presence?->resource;
$jid = explodeJid($room);
$capability = \App\Info::where('server', $jid['server'])
->where('node', '')
->first();
if (!$capability || !$capability->isMAM()) {
$this->user->messages()->where('jidfrom', $room)->delete();
}
// We clear the ping timer
ChatroomPings::getInstance()->clear($room);
// We clear the presences from the buffer cache and then the DB
$this->user->session->conferences()
->where('conference', $room)
->first()->presences()->delete();
$this->ajaxHttpGet();
if ($resource) {
$session = Session::instance();
$session->delete($room . '/' . $resource);
$pu = new Unavailable;
$pu->setTo($room)
->setResource($resource)
->request();
}
}
public function prepareConference(Conference $conference)
{
$view = $this->tpl();
$view->assign('conference', $conference);
return $view->draw('_rooms_room');
}
public function prepareRoomCounter(Conference $conference, $withAvatar = false)
{
$view = $this->tpl();
$view->assign('conference', $conference);
$view->assign('withAvatar', $withAvatar);
return $view->draw('_rooms_counter');
}
/**
* Join errors
*/
public function onConflict()
{
Toast::send($this->__('chatrooms.conflict'));
}
public function onRegistrationRequired($packet)
{
Toast::send($this->__('chatrooms.registrationrequired'));
$this->ajaxExit($packet->content);
}
public function onRemoteServerNotFound($packet)
{
Toast::send($this->__('chatrooms.remoteservernotfound'));
$this->ajaxExit($packet->content);
}
public function onRemoteServerTimeout($packet)
{
Toast::send($this->__('chatrooms.remoteservertimeout'));
$this->ajaxExit($packet->content);
}
public function onItemNotFound($packet)
{
Toast::send($this->__('chatrooms.itemnotfound'));
$this->ajaxExit($packet->content);
}
public function onNotAuthorized($packet)
{
Toast::send($this->__('chatrooms.notauthorized'));
$this->ajaxExit($packet->content);
}
public function onForbidden($packet)
{
Toast::send($this->__('chatrooms.forbidden'));
$this->ajaxExit($packet->content);
}
public function onJidMalformed($packet)
{
Toast::send($this->__('chatrooms.jidmalformed'));
$this->ajaxExit($packet->content);
}
public function onNotAcceptable($packet)
{
Toast::send($this->__('chatrooms.notacceptable'));
$this->ajaxExit($packet->content);
}
public function onServiceUnavailable($packet)
{
Toast::send($this->__('chatrooms.serviceunavailable'));
$this->ajaxExit($packet->content);
}
}