/**
  * Extracts a new response from a communicator.
  * 
  * This is the function that performs the actual receiving, while the
  * constructor is also involved in locks and registry sync.
  * 
  * @param Communicator $com       The communicator from which to extract
  *     the new response.
  * @param bool         $asStream  Whether to populate the argument values
  *     with streams instead of strings.
  * @param int          $sTimeout  If a response is not immediatly
  *     available, wait this many seconds. If NULL, wait indefinetly.
  *     Note that if an empty sentence is received, the timeout will be
  *     reset for another sentence receiving.
  * @param int          $usTimeout Microseconds to add to the waiting time.
  * 
  * @return void
  */
 private function _receive(Communicator $com, $asStream = false, $sTimeout = 0, $usTimeout = null)
 {
     do {
         if (!$com->getTransmitter()->isDataAwaiting($sTimeout, $usTimeout)) {
             throw new SocketException('No data within the time limit', SocketException::CODE_NO_DATA);
         }
         $type = $com->getNextWord();
     } while ('' === $type);
     $this->setType($type);
     if ($asStream) {
         for ($word = $com->getNextWordAsStream(), fseek($word, 0, SEEK_END); ftell($word) !== 0; $word = $com->getNextWordAsStream(), fseek($word, 0, SEEK_END)) {
             rewind($word);
             $ind = fread($word, 1);
             if ('=' === $ind || '.' === $ind) {
                 $prefix = stream_get_line($word, null, '=');
             }
             if ('=' === $ind) {
                 $value = fopen('php://temp', 'r+b');
                 $bytesCopied = ftell($word);
                 while (!feof($word)) {
                     $bytesCopied += stream_copy_to_stream($word, $value, 0xfffff, $bytesCopied);
                 }
                 rewind($value);
                 $this->setAttribute($prefix, $value);
                 continue;
             }
             if ('.' === $ind && 'tag' === $prefix) {
                 $this->setTag(stream_get_contents($word, -1, -1));
                 continue;
             }
             rewind($word);
             $this->unrecognizedWords[] = $word;
         }
     } else {
         for ($word = $com->getNextWord(); '' !== $word; $word = $com->getNextWord()) {
             if (preg_match('/^=([^=]+)=(.*)$/sS', $word, $matches)) {
                 $this->setAttribute($matches[1], $matches[2]);
             } elseif (preg_match('/^\\.tag=(.*)$/sS', $word, $matches)) {
                 $this->setTag($matches[1]);
             } else {
                 $this->unrecognizedWords[] = $word;
             }
         }
     }
 }