예제 #1
0
 public function handle(Command $command, ClientContext $context) : Generator
 {
     yield from $context->writeResponse(new Response(101, 'Capability list follows (multi-line)'));
     // Generate the list of capabilities that we support.
     $capabilities = ['VERSION 2', 'READER', 'POST', 'NEWNEWS', 'LIST ACTIVE', 'IMPLEMENTATION coderstephen/nntp server'];
     // If TLS is not already active, the STARTTLS is available.
     if (!$context->getSocket()->isCryptoEnabled()) {
         //array_splice($capabilities, -2, 0, ['STARTTLS']);
     }
     $data = implode("\r\n", $capabilities);
     yield from $context->writeData($data);
 }
예제 #2
0
 public function handle(Command $command, ClientContext $context) : Generator
 {
     yield from $context->writeResponse(new Response(215, 'List of newsgroups follows'));
     $groups = (yield from $context->getAccessLayer()->getGroups());
     $data = array_reduce($groups, function (string $s, Group $group) {
         switch ($group->status()) {
             case Group::POSTING_PERMITTED:
                 $status = 'y';
                 break;
             case Group::POSTING_NOT_PERMITTED:
                 $status = 'n';
                 break;
             case Group::POSTING_FORWARDED:
                 $status = 'm';
                 break;
             default:
                 $status = 'u';
                 break;
         }
         return $s . sprintf("%s %d %d %s\r\n", $group->name(), $group->highWaterMark(), $group->lowWaterMark(), $status);
     }, '');
     yield from $context->writeData($data);
 }
예제 #3
0
 public function handle(Command $command, ClientContext $context) : Generator
 {
     if (!$context->getAccessLayer()->isPostingAllowed()) {
         yield from $context->writeResponse(new Response(440, 'Posting not permitted'));
         return;
     }
     yield from $context->writeResponse(new Response(340, 'Send article to be posted'));
     $data = (yield from $context->readData());
     $article = Article::parse($data);
     try {
         yield from $context->getAccessLayer()->postArticle($article);
         yield from $context->writeResponse(new Response(240, 'Article received OK'));
     } catch (\Throwable $e) {
         yield from $context->writeResponse(new Response(441, 'Posting failed'));
     }
 }
예제 #4
0
 public function handle(Command $command, ClientContext $context) : Generator
 {
     // Make sure we have a valid cursor.
     if (!$context->getCursor()->valid()) {
         yield from $context->writeResponse(new Response(412, 'No newsgroup selected'));
         return;
     }
     // Try to move to the next article.
     if (!(yield from $context->getCursor()->next())) {
         yield from $context->writeResponse(new Response(421, 'No next article in this group'));
         return;
     }
     // Spit out the current article info.
     $article = $context->getCursor()->getArticle();
     yield from $context->writeResponse(new Response(223, '%d %s Article found', $article->number(), $article->id()));
 }
예제 #5
0
 public function handle(Command $command, ClientContext $context) : Generator
 {
     if ($command->argCount() !== 1) {
         yield from $context->writeResponse(new Response(501, 'Invalid number of arguments'));
         return;
     }
     try {
         $name = $command->arg(0);
         $cursor = (yield from $context->getAccessLayer()->getGroupCursor($name));
         $context->setCursor($cursor);
     } catch (NotFoundException $e) {
         yield from $context->writeResponse(new Response(411, 'No such newsgroup'));
         return;
     }
     $group = $context->getCursor()->getGroup();
     yield from $context->writeResponse(new Response(211, $group->count() . ' ' . $group->lowWaterMark() . ' ' . $group->highWaterMark() . ' ' . $group->name() . ' Group successfully selected'));
 }
예제 #6
0
 public function handle(Command $command, ClientContext $context) : Generator
 {
     if ($command->argCount() === 0) {
         $group = $this->currentGroup;
     }
     $name = $command->arg(0);
     $group = (yield from $context->getAccessLayer()->getGroupByName($name));
     if (!$group) {
         yield from $context->writeResponse(new Response(411, 'No such newsgroup'));
         return;
     }
     $context->setCurrentGroup($group->name());
     $context->setCurrentArticle($group->lowWaterMark());
     yield from $context->writeResponse(new Response(211, $group->count() . ' ' . $group->lowWaterMark() . ' ' . $group->highWaterMark() . ' ' . $group->name() . ' Group successfully selected'));
 }
예제 #7
0
 public function handle(Command $command, ClientContext $context) : Generator
 {
     yield from $context->writeResponse(new Response(200, 'Reader mode already active'));
 }
예제 #8
0
 public function handle(Command $command, ClientContext $context) : Generator
 {
     yield from $context->writeResponse(new Response(100, 'Help text follows (multi-line)'));
     $data = implode("\r\n", ['article [message-id|number]', 'body [message-id|number]', 'capabilities', 'date', 'group group', 'head [message-id|number]', 'help', 'last', 'list active', 'listgroup', 'newgroups', 'newnews', 'next', 'post', 'quit', 'stat']);
     yield from $context->writeData($data);
 }
예제 #9
0
 protected function fetchArticle(Command $command, ClientContext $context) : Generator
 {
     // Current article?
     if ($command->argCount() === 0) {
         if (!$context->getCursor()->valid()) {
             yield from $context->writeResponse(new Response(412, 'No newsgroup selected'));
             return;
         }
         return $context->getCursor()->getArticle();
     } elseif (is_numeric($command->arg(0))) {
         $number = (int) $command->arg(0);
         if (!$context->getCursor()->valid()) {
             yield from $context->writeResponse(new Response(412, 'No newsgroup selected'));
             return;
         }
         if (!(yield from $context->getCursor()->seek($number))) {
             yield from $context->writeResponse(new Response(423, 'No article with that number'));
             return;
         }
         return $context->getCursor()->getArticle();
     } else {
         $article = (yield from $context->getAccessLayer()->getArticleById($command->arg(0)));
         if (!$article) {
             yield from $context->writeResponse(new Response(430, 'No article with that message-id'));
             return;
         }
     }
     return $article;
 }
예제 #10
0
 /**
  * Services requests for a connected client.
  *
  * Manages the server-side state for the remote client and interprets client commands.
  */
 private function handleClient(Socket $socket) : Generator
 {
     yield from log()->log(Log::INFO, 'Accepted client from %s:%d on %s:%d', $socket->getRemoteAddress(), $socket->getRemotePort(), $socket->getLocalAddress(), $socket->getLocalPort());
     // Create a new context object for this client.
     $context = new ClientContext($socket, $this->encoder, $this->accessLayer);
     try {
         // Send a welcome message.
         $welcome = new Response(200, 'Ready');
         yield from $context->writeResponse($welcome);
         // Command loop
         while ($socket->isOpen()) {
             // Parse incoming commands.
             $command = (yield from $context->readCommand());
             // Determine the command name and choose how to handle it.
             $handler = null;
             switch ($command->name()) {
                 // Mandatory commands
                 case 'CAPABILITIES':
                     $handler = $this->getHandler(handlers\CapabilitiesHandler::class);
                     break;
                 case 'HEAD':
                     $handler = $this->getHandler(handlers\HeadHandler::class);
                     break;
                 case 'HELP':
                     $handler = $this->getHandler(handlers\HelpHandler::class);
                     break;
                     // We don't advertise MODE support, but some readers need it
                 // We don't advertise MODE support, but some readers need it
                 case 'MODE':
                     $handler = $this->getHandler(handlers\ModeHandler::class);
                     break;
                 case 'STAT':
                     $handler = $this->getHandler(handlers\StatHandler::class);
                     break;
                 case 'QUIT':
                     yield from $context->writeResponse(new Response(205, 'Closing connection'));
                     break 2;
                     // stop command loop
                     // LIST commands
                 // stop command loop
                 // LIST commands
                 case 'LIST':
                     $handler = $this->getHandler(handlers\ListHandler::class);
                     break;
                     // NEWNEWS commands
                 // NEWNEWS commands
                 case 'NEWNEWS':
                     $handler = $this->getHandler(handlers\NewNewsHandler::class);
                     break;
                     // POST commands
                 // POST commands
                 case 'POST':
                     $handler = $this->getHandler(handlers\PostHandler::class);
                     break;
                     // READER commands
                 // READER commands
                 case 'ARTICLE':
                     $handler = $this->getHandler(handlers\ArticleHandler::class);
                     break;
                 case 'BODY':
                     $handler = $this->getHandler(handlers\BodyHandler::class);
                     break;
                 case 'DATE':
                     $handler = $this->getHandler(handlers\DateHandler::class);
                     break;
                 case 'GROUP':
                     $handler = $this->getHandler(handlers\GroupHandler::class);
                     break;
                 case 'LAST':
                     $handler = $this->getHandler(handlers\LastHandler::class);
                     break;
                 case 'LISTGROUP':
                     $handler = $this->getHandler(handlers\ListGroupHandler::class);
                     break;
                 case 'NEWGROUPS':
                     $handler = $this->getHandler(handlers\NewGroupsHandler::class);
                     break;
                 case 'NEXT':
                     $handler = $this->getHandler(handlers\NextHandler::class);
                     break;
             }
             // Unknown command
             if (!$handler) {
                 yield from $context->writeResponse(new Response(500, 'Unknown command'));
             } else {
                 // Execute the selected command handler.
                 try {
                     yield from $handler->handle($command, $context);
                 } catch (\Throwable $e) {
                     yield from log()->log(Log::ERROR, 'Error handling command: ' . $e);
                     yield from $context->writeResponse(new Response(502, 'Server error'));
                 }
             }
         }
     } catch (UnreadableException $e) {
         // Client disconnected.
     } catch (UnwritableException $e) {
         // Client disconnected.
     } catch (ClosedException $e) {
         // Client disconnected.
     }
     yield from log()->log(Log::INFO, 'Disconnected client from %s:%d on %s:%d', $socket->getRemoteAddress(), $socket->getRemotePort(), $socket->getLocalAddress(), $socket->getLocalPort());
     // Close the connection to the client.
     if ($socket->isOpen()) {
         $socket->close();
     }
 }
예제 #11
0
 public function handle(Command $command, ClientContext $context) : Generator
 {
     yield from $context->writeResponse(new Response(111, date('YmdHis')));
 }
예제 #12
0
 public function handle(Command $command, ClientContext $context) : Generator
 {
     yield from $context->writeResponse(new Response(382, 'Continue with TLS negotiation'));
     yield from $context->getSocket()->enableCrypto(self::CRYPTO_METHOD);
 }