#!/usr/bin/php -q registerIdentityFunction (array ($this, 'discoInfo')); $XEP0030->registerItemFunction (array ($this, 'discoItems')); $XEP0050 = new tiggerXMPP_XEP_0050 ($this); $XEP0050->setCommandHandler (array ($this, 'commandHandler')); } // }}} // {{{ logMessage /** * Log an incoming message * * @param object $Tag * * @access protected * @return void **/ protected function logMessage ($Tag) { // Retrive the direction if (($Direction = $this->getDirection ($Tag)) === false) return; // Retrive the owner of the packet if (strlen ($Owner = $this->getOwner ($Tag, $Direction)) < 2) return; $Owner = $this->getJID (true, true, false, $Owner); // Check if the owner is subscribed if (!is_dir ('history/' . $Owner)) return; // Retrive the Opponent if (strlen ($Opponent = $this->getOpponent ($Tag, $Direction)) < 2) return; $Opponent = $this->getJID (true, true, false, $Opponent); // Retrive the message from payload if (!is_string ($Msg = $Tag->getMessage ($this->getLanguage ()))) return; // Its senseless to log OTR if (substr ($Msg, 0, 5) == '?OTR:') return; // Start/Resume conversation if (!isset ($this->Conversations [$Owner])) $this->Conversations [$Owner] = array (); $convBase = 'history/' . $Owner . '/' . $Opponent; if (!isset ($this->Conversations [$Owner][$Opponent])) // There was never a conversation with this opponent before if (!is_dir ($convBase)) { if (!mkdir ($convBase)) return; $this->Conversations [$Owner][$Opponent] = array ($convBase . '/' . time (), time ()); // Check wheter to resume a conversation } elseif (is_object ($d = @dir ($convBase))) { $t = time (); $f = false; while ($f = $d->read ()) if ($t - filemtime ($convBase . '/' . $f) < self::CONVERSATION_LIFETIME) { $this->Conversations [$Owner][$Opponent] = array ($convBase . '/' . $f, time ()); $f = true; break; } $d->close (); if (!$f) $this->Conversations [$Owner][$Opponent] = array ($convBase . '/' . time (), time ()); // Strange error... } else { return; } // Check the lifetime if (time () - ($LastAction = $this->Conversations [$Owner][$Opponent][1]) > self::CONVERSATION_LIFETIME) $this->Conversations [$Owner][$Opponent] = array ($convBase . '/' . time (), $LastAction = time ()); $File = $this->Conversations [$Owner][$Opponent][0]; if (!is_resource ($f = @fopen ($File, 'a'))) return; fwrite ($f, $Direction . ':' . time () . ':' . base64_encode ($Msg) . "\n"); fclose ($f); } // }}} // {{{ discoInfo /** * Check wheter a requested domain is exposed to a given sm-domain (and forward to service-discovery) * * @param string $JID * @param stirng $Receipient * * @access public * @return array **/ public function discoInfo ($JID, $Receipient, $Node = null) { // Check if we are bound to the queried domain if (!$this->boundDomain ($JID)) return false; // Return the root-identity if ($Node === null) return array (new tiggerXMPP_XEP_0030_Identity ('tiggersWelt.net Message Archiver', 'component', 'archive')); // Retrive the owner of the collection $Owner = basename ($this->getJID (true, true, false, $Receipient)); // Check if opponent-node exists $Opponent = basename ($this->getJID (true, true, false, $Node)); if (($Node [0] == '.') || !is_dir ('history/' . $Owner . '/' . $Opponent)) return false; // Check if a conversation was selected $TS = basename ($this->getJID (false, false, true, $Node)); // Return identitiy for the node if (strlen ($TS) == 0) return array (new tiggerXMPP_XEP_0030_Identity ('Conversations with ' . $Opponent, 'component', 'archive')); // Handle the resource if (($p = strpos ($TS, ':')) !== false) { $Command = substr ($TS, $p + 1); $TS = substr ($TS, 0, $p); } else $Command = null; // Check if there is a conversation if ((intval ($TS) == 0) || !is_file ('history/' . $Owner . '/' . $Opponent . '/' . $TS)) return false; if ($Command === null) return array (new tiggerXMPP_XEP_0030_Identity (date ('r', $TS), 'component', 'archive', '', array (tiggerXMPP_XEP_0050::XEP_NAMESPACE))); if ($Command == 'replay') return array (new tiggerXMPP_XEP_0030_Identity ('Replay this conversation', 'automation', 'command-node', '', array (tiggerXMPP_XEP_0050::XEP_NAMESPACE))); elseif ($Command == 'remove') return array (new tiggerXMPP_XEP_0030_Identity ('Remove this conversation', 'automation', 'command-node', '', array (tiggerXMPP_XEP_0050::XEP_NAMESPACE))); return array (); } // }}} // {{{ discoItems /** * Retrive items below a given node/jid * * @param string $JID * @param string $Receipient * @param string $Node (optiona) * * @access public * @return array **/ public function discoItems ($JID, $Receipient, $Node = null) { $Items = array (); // Check if we are bound to the queried domain if ($this->boundDomain ($JID)) { // Retrive owner of the collection $Owner = basename ($this->getJID (true, true, false, $Receipient)); // Retrive list of conversation-opponentes if ($Node === null) { if (is_dir ($p = 'history/' . $Owner) && is_object ($d = @dir ($p))) { while ($f = $d->read ()) if (($f [0] != '.') && is_dir ($p . '/' . $f)) $Items [] = new tiggerXMPP_XEP_0030_Item ($JID, $f, $f, $JID); $d->close (); } // Retrive list of conversations for a given opponent } elseif (strlen ($TS = basename ($this->getJID (false, false, true, $Node))) == 0) { $Opponent = basename ($this->getJID (true, true, false, $Node)); if (($Opponent [0] != '.') && is_object ($d = @dir ($p = 'history/' . $Owner . '/' . $Opponent))) while ($f = $d->read ()) if (is_file ($p .'/'. $f)) $Items [] = new tiggerXMPP_XEP_0030_Item ($JID, date ('r', $f), $Opponent . '/' . $f, $JID); // Append commands for a conversation } else { $Opponent = basename ($this->getJID (true, true, false, $Node)); if (($Opponent [0] != '.') && is_file ('history/' . $Owner . '/' . $Opponent . '/' . $TS)) { $Items [] = new tiggerXMPP_XEP_0030_Item ($JID, 'Replay this conversation', $Opponent . '/' . $TS . ':replay', $JID); $Items [] = new tiggerXMPP_XEP_0030_Item ($JID, 'Remove this conversation', $Opponent . '/' . $TS . ':remove', $JID); } } } return $Items; } // }}} // {{{ commandHandler /** * Execute a command * * @param object $XEP * @param object $Tag * @param string $JID * @param string $Node * @param string $Receipient * * @access public * @return bool **/ public function commandHandler ($XEP, $Tag, $JID, $Node, $Receipient) { // Check if we are bound to the called domain if (!$this->boundDomain ($JID)) return false; // Parse all informations $Owner = $this->getJID (true, true, false, $Receipient); $Opponent = basename ($this->getJID (true, true, false, $Node)); $TS = basename ($this->getJID (false, false, true, $Node)); if (($p = strpos ($TS, ':')) !== false) { $Command = substr ($TS, $p + 1); $TS = substr ($TS, 0, $p); } else $Command = 'replay'; // Check the data if (!is_file ('history/' . $Owner . '/' . $Opponent . '/' . $TS)) return false; // Run the command switch ($Command) { case 'remove': // Try to remove if (!unlink ('history/' . $Owner . '/' . $Opponent . '/' . $TS)) return false; // Remove directories (if empty) if (rmdir ('history/' . $Owner . '/' . $Opponent)) rmdir ('history/' . $Owner); return true; case 'replay': // Try to open the log if (!is_resource ($f = fopen ('history/' . $Owner . '/' . $Opponent . '/' . $TS, 'r'))) return false; $xmppMessage = tiggerXMPP_Message::newTag ($Receipient, $this->getJID (true, true, true)); $xmppMessage->setType (tiggerXMPP_Message::TYPE_CHAT); $xmppMessage->setMessage ('Replaying Conversation to ' . $Opponent . ' on ' . date ('r', $TS)); $this->sendXML ($xmppMessage); while ($line = fgets ($f, 4096)) { // Parse the line if (($p = strpos ($line, ':')) === false) continue; $Direction = substr ($line, 0, $p); $line = substr ($line, $p + 1); if (($p = strpos ($line, ':')) === false) continue; $TS = intval (substr ($line, 0, $p)); $Message = base64_decode (rtrim (substr ($line, $p + 1))); // Generate XMPP-Message $xmppMessage = tiggerXMPP_Message::newTag ($Receipient, $this->getJID (true, true, true)); $xmppMessage->setType (tiggerXMPP_Message::TYPE_CHAT); $xmppMessage->setMessage ('<' . ($Direction == self::DIRECTION_IN ? $Opponent : $Owner) . '> ' . $Message); $xmppMessage->setTimestamp ($TS, ($Direction == self::DIRECTION_IN ? $Opponent : $Owner), 'Archived message'); $this->sendXML ($xmppMessage); } fclose ($f); return true; default: return false; } // Assume true here return true; } // }}} } $Logger = new Example_Logger ('logger', '127.0.0.1', 5200, tiggerXMPP_Stream::DEBUG_WARN); if (!$Logger->authenticate ('logger-password', 'logger-username')) die ('Authentication failed'); $Base = new phpEvents_Base; $Base->addEvent ($Logger); $Base->loop (); ?>