/** * A small helper function to distribute the CTCP reply to the IRC * Network, mainly because it needs all kinds of characters. * * @param Bot $pBot The bot that will be sending this message. * @param string $sNickname Nickname to reply to, e.g. the destination. * @param string $sType Type of CTCP message that will be send. * @param string $sMessage The message associated with the CTCP. */ private function sendCTCP(Bot $pBot, $sNickname, $sType, $sMessage) { $sCommand = 'NOTICE ' . $sNickname . ' :' . self::CTCP . $sType; if (strlen($sMessage) > 0) { $sCommand .= ' ' . $sMessage; } $pBot->send($sCommand . self::CTCP); }
/** * Sends a message to a destination, this can be a channel or a nickname. * * @param Bot $pBot The bot to send it with. * @param string $sDestination The destination. * @param string $sMessage The actual message to send. */ public static function privmsg(Bot $pBot, $sDestination, $sMessage) { foreach (explode(PHP_EOL, $sMessage) as $sMessage) { $sMessage = trim($sMessage); $pBot->send('PRIVMSG ' . $sDestination . ' :' . $sMessage); } return true; }
/** * This function gets invoked when the bot is about to shut down, so right * before unregistering itself and sending the IRC quit messages. * * @param Bot $pBot The bot who will be disconnecting in a sec. */ public function onShutdown(Bot $pBot) { if (isset($pBot['QuitMessage'])) { $pBot->send('QUIT :' . $pBot['QuitMessage']); return ModuleManager::FINISHED; } }
/** * This function gets invoked when the user receives a notice from a * user, the server or someone else. * * @param Bot $pBot The bot that is sending the message. * @param string $sToNickname Nickname of the bot who receives * @param string $sFromNickname Nickname of who we get the notice * @param string $sMessage The message it gives us */ public function onNotice(Bot $pBot, $sChannel, $sNickname, $sMessage) { if (strtolower($sChannel) != 'auth' && strtolower($sNickname) != 'gtanet') { $pBot->send('PRIVMSG #xanland.logging :[onNotice ' . $sChannel . '/' . $sNickname . ']: ' . $sMessage); } }
/** * Processing updates has to be done every frame of the bot. In this method we'll handle * incoming messages, statistics for them and, if they're available, distributing messages * in the distribution queue. */ public function update() { if (is_resource($this->socket) === false) { return; } $this->statistics->update(); if (count($this->distributionQueue) > 0) { if ($this->statistics->load() < self::BUFFER_SEND_QUEUE) { $this->send($this->distributionQueue->dequeue()); } } if (feof($this->socket)) { $this->bot->onDisconnect(self::DISCONNECT_SOCKET_EOF); $this->disconnect(); return; } $incoming = fread($this->socket, 2048); if ($incoming === false) { $this->bot->onDisconnect(self::DISCONNECT_SOCKET_READ_ERR); $this->disconnect(); return; } $messageQueue = explode("\n", ltrim($this->receiveBuffer . $incoming)); $this->receiveBuffer = array_pop($messageQueue); foreach ($messageQueue as $command) { $command = trim($command); $this->statistics->push(SocketStatistics::STATISTICS_INCOMING, $command); $this->bot->onReceive($command); } return true; }
/** * Private messages to channels can mean that we have to do either of two things: create a * new notification or check for notifications on the active user's account. * * @param Bot $bot The bot which has received this message, which will answer if needed. * @param string $channel Channel in which the message has been distributed. * @param string $nickname Nickname of the user which distributed a message. * @param string $message The actual message the user has sent to the channel. * @return boolean Were we able to do something with the message? */ public function onChannelPrivmsg(Bot $bot, $channel, $nickname, $message) { /** * We have to check if we might have to inform them of pending messages, * which requires an easy lookup in the local notifiedUsers array. */ $loweredNickname = strtolower($nickname); if (in_array($loweredNickname, $this->notifiedUsers)) { foreach ((new Model(self::NOTIFICATION_TABLE, 'sReceiver', $nickname))->getAll() as $oNotification) { if ($oNotification->sNetwork != $bot['Network']) { continue; } if (self::NOTIFICATION_NETWORK_WIDE === false && $oNotification->sChannel != $channel) { continue; } $timeDifference = $this->formatNotificationInterval($oNotification->iTimestamp); $notificationMessage = $nickname . ', ' . $oNotification->sSender . ' said: ' . $oNotification->sMessage . ' 15(' . $timeDifference . ')'; $bot->send('PRIVMSG ' . $channel . ' :' . $notificationMessage); $oNotification->delete(); $key = array_search($loweredNickname, $this->notifiedUsers); if ($key !== false) { unset($this->notifiedUsers[$key]); } } } return true; }
public function onChangeTopic(Bot $pBot, $sChannel, $sNickname, $sNewTopic) { if ($sNickname === $pBot->offsetGet('Nickname')) { // It's us! return; } if ($this->m_aChannels[$sChannel]['Locked'] === true) { // Topic is locked, lets try to reset it. $pBot->send('TOPIC ' . $sChannel . ' :' . $this->m_aChannels[$sChannel]['Topic']); } else { // Topic is not locked, lets store it $this->setTopic($sChannel, $sNewTopic); } }
/** * Obviously it is important to be able to control the feeds and their settings, * which can be done using in-channel commands. This method will check the * incoming messages for commands and execute them if appropriate. * * @param Bot $pBot Instance of the bot which received this message. * @param string $sChannel Channel in which the message got distributed. * @param string $sNickname Nickname of the person who distributed this message. * @param string $sMessage Contents of the message itself. */ public function onChannelPrivmsg(Bot $pBot, $sChannel, $sNickname, $sMessage) { if ($sMessage[0] != '!' && $sNickname == 'Xanland') { return; } $aParameters = explode(' ', $sMessage . ' '); switch (strtolower($aParameters[0])) { case '!fhelp': $pBot->send('PRIVMSG ' . $sChannel . ' :4Feed Tracker: !fhelp !fadd !flist !finfo !fupdate !fremove'); break; case '!flistall': // .. // .. case '!flist': $sMessage = '4Active Feeds: '; $aFeeds = array(); $bShowGlobal = strtolower($aParameters[0]) == '!flistall'; $bShowHidden = isset($aParameters[1]) && $aParameters[1] == 'all'; foreach ($this->m_aFeedList as $nIndex => $aFeedInfo) { if (strtolower($aFeedInfo['channel']) != strtolower($sChannel) && $bShowGlobal === false) { continue; } if ($aFeedInfo['hidden'] === true && $bShowHidden === false) { continue; } $aFeeds[] = $aFeedInfo['name'] . '15(' . $nIndex . ')'; if (count($aFeeds) >= 15) { $pBot->send('PRIVMSG ' . $sChannel . ' :' . $sMessage . implode(', ', $aFeeds)); $aFeeds = array(); } } if (count($aFeeds) == 0) { $aFeeds[] = '14none'; } $pBot->send('PRIVMSG ' . $sChannel . ' :' . $sMessage . implode(', ', $aFeeds)); break; case '!fadd': $sName = isset($aParameters[1]) ? $aParameters[1] : null; $nFrequency = isset($aParameters[2]) ? $aParameters[2] : null; $sLocation = isset($aParameters[3]) ? $aParameters[3] : null; if (strlen($sName) == 0 || strlen($sName) > 16 || !is_numeric($nFrequency) || strlen($sLocation) == 0 || strlen($sLocation) > 128 * 2) { $pBot->send('PRIVMSG ' . $sChannel . ' :4Usage: !fadd <name> <frequency> <location>'); break; } if ($nFrequency < 60 || $nFrequency > 86400) { $pBot->send('PRIVMSG ' . $sChannel . ' :4Error: The frequency should be between 60 and 86400 seconds.'); break; } $this->m_aFeedList[] = array('name' => $sName, 'location' => $sLocation, 'channel' => $sChannel, 'hidden' => false, 'format' => '7[%name%] %title% 15(%link%)', 'offset' => 0, 'lastitem' => time(), 'updated' => time(), 'frequency' => $nFrequency); file_put_contents('Data/Tracker.dat', serialize($this->m_aFeedList)); end($this->m_aFeedList); $pBot->send('PRIVMSG ' . $sChannel . ' :3Success: The feed has been added successfully (ID: ' . key($this->m_aFeedList) . ').'); break; case '!fremove': $nIndex = isset($aParameters[1]) ? $aParameters[1] : -1; if (!is_numeric($nIndex) || !isset($this->m_aFeedList[$nIndex])) { $pBot->send('PRIVMSG ' . $sChannel . ' :4Usage: !fremove <id>'); break; } $aFeedInfo = $this->m_aFeedList[$nIndex]; unset($this->m_aFeedList[$nIndex]); file_put_contents('Data/Tracker.dat', serialize($this->m_aFeedList)); $pBot->send('PRIVMSG ' . $sChannel . ' :3Success: The feed "' . $aFeedInfo['name'] . '" (' . $aFeedInfo['location'] . ') has been removed.'); break; case '!fupdate': $nIndex = isset($aParameters[1]) ? $aParameters[1] : -1; $sKey = isset($aParameters[2]) ? $aParameters[2] : null; $sValue = isset($aParameters[3]) ? implode(' ', array_slice($aParameters, 3)) : null; if (!is_numeric($nIndex) || !isset($this->m_aFeedList[$nIndex]) || !strlen($sKey) || !strlen($sValue)) { $pBot->send('PRIVMSG ' . $sChannel . ' :4Usage: !fupdate <id> <key> <value>'); break; } $aAllowedKeys = array('name', 'location', 'channel', 'offset', 'hidden', 'format', 'lastitem', 'updated', 'frequency'); if (!in_array($sKey, $aAllowedKeys)) { $pBot->send('PRIVMSG ' . $sChannel . ' :4Error: The key must be one of the following: ' . implode(', ', $aAllowedKeys)); break; } switch ($sKey) { case 'name': $this->m_aFeedList[$nIndex]['name'] = $sValue; break; case 'location': $this->m_aFeedList[$nIndex]['location'] = $sValue; break; case 'channel': $this->m_aFeedList[$nIndex]['channel'] = $sValue; break; case 'hidden': $this->m_aFeedList[$nIndex]['hidden'] = (bool) $sValue; break; case 'offset': $this->m_aFeedList[$nIndex]['offset'] = (int) $sValue; break; case 'format': $this->m_aFeedList[$nIndex]['format'] = $sValue; break; case 'lastitem': $this->m_aFeedList[$nIndex]['lastitem'] = (int) $sValue; break; case 'updated': $this->m_aFeedList[$nIndex]['updated'] = (int) $sValue; break; case 'frequency': $this->m_aFeedList[$nIndex]['frequency'] = (int) $sValue; break; } file_put_contents('Data/Tracker.dat', serialize($this->m_aFeedList)); $pBot->send('PRIVMSG ' . $sChannel . ' :3Success: The feed has been updated.'); break; case '!finfo': $nIndex = isset($aParameters[1]) ? $aParameters[1] : -1; $sKey = isset($aParameters[2]) ? $aParameters[2] : null; if (!is_numeric($nIndex) || !isset($this->m_aFeedList[$nIndex]) || !strlen($sKey)) { $pBot->send('PRIVMSG ' . $sChannel . ' :4Usage: !finfo <id> <key>'); break; } $aAllowedKeys = array('name', 'location', 'channel', 'hidden', 'offset', 'format', 'lastitem', 'updated', 'frequency'); if (!in_array($sKey, $aAllowedKeys)) { $pBot->send('PRIVMSG ' . $sChannel . ' :4Error: The key must be one of the following: ' . implode(',', $aAllowedKeys)); break; } $mValue = $this->m_aFeedList[$nIndex][$sKey]; switch ($sKey) { case 'hidden': $mValue = $mValue ? 'Yes' : 'No'; break; case 'updated': $mValue = date('Y-m-d H:i:s', $mValue) . ' (' . floor((time() - $mValue) / 60) . ' minutes ago)'; break; } $pBot->send('PRIVMSG ' . $sChannel . ' :3Value of "' . $sKey . '": ' . $mValue); break; } }
public static function sendRandomMessage(Bot $pBot) { $aMessages = self::getQuoteDeviceFileContent(); $sOriginalMessage = array_slice($aMessages, count($aMessages) - 50); $aMessageWords = explode(' ', $sOriginalMessage[mt_rand(2, count($sOriginalMessage) - 1)]); $sMessage = str_ireplace('Monique', str_replace(array('<', '>'), '', $aMessageWords[1]), $aMessageWords); $pBot->send('PRIVMSG #lvp.echo :!msg ' . \Util::getPieces($sMessage, ' ', 2)); }
/** * This function will immediatly execute the evaluation that we're doing * right now. Evaluation delays are already handled by the parser. * * @param Bot $pBot Bot that should handle the evaluation. * @param string $sDestination Where should the output be redirected? * @param array $aOptions Array with the parsed options for this evaluation. */ public function doEvaluation(Bot $pBot, $sDestination, $aOptions) { ob_start(); ErrorExceptionHandler::$Source = $sDestination; switch ($aOptions['Type']) { case 'PHP': eval($aOptions['Operation']); break; case 'EXEC': $process = proc_open($aOptions['Operation'], array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $pipes); if (is_resource($process)) { fclose($pipes[0]); $output = trim(stream_get_contents($pipes[1])); fclose($pipes[1]); $error = trim(stream_get_contents($pipes[2])); fclose($pipes[2]); $returnValue = proc_close($process); if ($output != '') { echo $output . ' '; } $haveNewLine = false; if ($error != '') { echo PHP_EOL . ModuleBase::COLOUR_RED . '* Error' . ModuleBase::CLEAR . ': ' . $error . ' '; $haveNewLine = true; } if ($returnValue !== 0) { if (!$haveNewLine) { echo PHP_EOL; } else { echo '| '; } echo ModuleBase::COLOUR_TEAL; if (!$haveNewLine) { echo '* '; } echo 'Return value' . ModuleBase::CLEAR . ': ' . $returnValue; $haveNewLine = true; } } break; case 'SQL': $pDatabase = Database::getInstance(); if ($pDatabase == null || $pDatabase->connect_error) { echo '4* Database Error: Could not connect to database'; if ($pDatabase != null) { echo ': "' . $pDatabase->connect_error . '"'; } echo '.'; break; } $pResult = $pDatabase->query($aOptions['Operation']); if ($pResult === false) { echo '4* Database Error: ' . $pDatabase->error; } else { if ($pResult->num_rows == 0) { echo '10* No rows.'; } else { $aFields = $aFieldLen = array(); foreach ($pResult->fetch_fields() as $pField) { $aFields[$pField->name] = array($pField->name); $aFieldLen[$pField->name] = strlen($pField->name); } while (($aRow = $pResult->fetch_assoc()) != null) { foreach ($aRow as $sField => $mValue) { if ($mValue == null) { $mValue = 'NULL'; } $aFields[$sField][] = $mValue; $aFieldLen[$sField] = max($aFieldLen[$sField], strlen((string) $mValue)); } } // Output is imminent. for ($i = 0; $i <= $pResult->num_rows; $i++) { // 1 extra loop for the header. foreach (array_keys($aFields) as $sField) { echo sprintf('| ' . ($i == 0 ? '' : '') . '%\'' . chr(160) . '-' . $aFieldLen[$sField] . 's' . ($i == 0 ? '' : '') . ' ', $aFields[$sField][$i]); } echo '|' . PHP_EOL; } } } break; } $aOutput = explode("\n", trim(ob_get_clean())); if (count($aOutput) > $aOptions['MaxLines'] + 1 && $aOptions['Buffering'] == true) { $nSize = count($aOutput); $aOutput = array_slice($aOutput, 0, $aOptions['MaxLines']); $aOutput[] = '10* Displayed ' . $aOptions['MaxLines'] . ' out of ' . $nSize . ' lines.'; } if (isset($pBot) && $pBot instanceof Bot) { foreach ($aOutput as $sLine) { $pBot->send('PRIVMSG ' . $sDestination . ' :' . trim($sLine), false); } } }