
function message_parse($rawmessage) {
  global $attachment_delete_alternative,$attachment_uudecode,$www_charset;
  global $iconv_enable;
  // Read the header of the message:
  $count_rawmessage=count($rawmessage);
  $message = new messageType;
  $rawheader=array();
  $i=0;
  while ($rawmessage[$i] != "") {
    $rawheader[]=$rawmessage[$i];
    $i++;
  }
  // Parse the Header:
  $message->header=parse_header($rawheader);
  // Now we know if the message is a mime-multipart message:
  $content_type=split("/",$message->header->content_type[0]);
  if ($content_type[0]=="multipart") {
    $message->header->content_type=array();
    // We have multible bodies, so we split the message into its parts
    $boundary="--".$message->header->content_type_boundary;
    // lets find the first part
    while($rawmessage[$i] != $boundary)
      $i++;
    $i++;
    $part=array();
    while($i<=$count_rawmessage) {
      if (($rawmessage[$i]==$boundary) || ($i==$count_rawmessage-1) ||
          ($rawmessage[$i]==$boundary.'--')) {
        $partmessage=message_parse($part);
        // merge the content-types of the message with those of the part
        for ($o=0; $o<count($partmessage->header->content_type); $o++) {
          $message->header->content_type[]=
            $partmessage->header->content_type[$o];
          $message->header->content_type_charset[]=
            $partmessage->header->content_type_charset[$o];
          $message->header->content_type_name[]=
            $partmessage->header->content_type_name[$o];
          $message->header->content_type_format[]=
            $partmessage->header->content_type_format[$o];
          $message->body[]=$partmessage->body[$o];
        }
        $part=array();
      } else {
        if ($i<$count_rawmessage)
          $part[]=$rawmessage[$i];
      }
      if ($rawmessage[$i]==$boundary.'--') break;
      $i++;
    }
    // Is this a multipart/alternative multipart-message? Do we have to
    // delete all non plain/text parts?
    if (($attachment_delete_alternative) &&
        ($content_type[1]=="alternative")) {
      $plaintext=false;
      for ($o=0; $o<count($message->header->content_type); $o++) {
        if ($message->header->content_type[$o]=="text/plain")
          $plaintext=true; // we found at least one text/plain
      }
      if ($plaintext) {    // now we can delete the other parts
        for ($o=0; $o<count($message->header->content_type); $o++) {
          if ($message->header->content_type[$o]!="text/plain") {
            unset($message->header->content_type[$o]);
            unset($message->header->content_type_name[$o]);
            unset($message->header->content_type_charset[$o]);
            unset($message->header->content_type_format[$o]);
            unset($message->body[$o]);
          }
        }
      }
    }
  } else {
    // No mime-attachments in the message:
    $body="";
    $uueatt=0; // as default we have no uuencoded attachments
    for($i++;$i<$count_rawmessage; $i++) {
      // do we have an inlay uuencoded file?
      if ((strtolower(substr($rawmessage[$i],0,5))!="begin") ||
          ($attachment_uudecode==false)) {
        $body.=$rawmessage[$i]."\n";
      // yes, it seems, we have!
      } else {
        $old_i=$i;
        $uue_infoline_raw=$rawmessage[$i];
        $uue_infoline=explode(" ",$uue_infoline_raw);
        $uue_data="";
        $i++;
        while($rawmessage[$i]!="end") {
          if (strlen(trim($rawmessage[$i])) > 2)
            $uue_data.=$rawmessage[$i]."\n";
          $i++;
        }
        // now write the data in an attachment
        $uueatt++;
        $message->body[$uueatt]=uudecode($uue_data);
        $message->header->content_type_name[$uueatt]="";
        for ($o=2; $o<count($uue_infoline); $o++)
          $message->header->content_type_name[$uueatt].=$uue_infoline[$o];
        $message->header->content_type[$uueatt]=
          get_mimetype_by_filename($message->header->content_type_name[$uueatt]);
      }
    }
    if ($message->header->content_type[0]=="text/plain") {
      $body=decode_body($body,$message->header->content_transfer_encoding);
      $body=recode_charset(rtrim($body),
                           $message->header->content_type_charset[0],
                           $www_charset);
      if ($body=="") $body=" ";
      
    }
    $message->body[0]=$body;
  }
    if (!isset($message->header->content_type_charset))
      $message->header->content_type_charset=array($www_charset);
    if (!isset($message->header->content_type_name))
      $message->header->content_type_name=array("unnamed");
    if (!isset($message->header->content_type_format))
      $message->header->content_type_format=array("fixed");
  for ($o=0; $o<count($message->body); $o++) {
    if (!isset($message->header->content_type_charset[$o]))
      $message->header->content_type_charset[$o]=$www_charset;
    if (!isset($message->header->content_type_name[$o]))
      $message->header->content_type_name[$o]="unnamed";
    if (!isset($message->header->content_type_format[$o]))
      $message->header->content_type_format[$o]="fixed";
  }
  return $message;
}


/*
 * read an article from the newsserver or the spool-directory
 *
 * $id: the Message-ID of an article
 * $bodynum: the number of the attachment:
 *          -1: return only the header without any bodies or attachments.
 *           0: the body
 *           1: the first attachment...
 *
 * The function returns an article as an messageType or false if the article
 * doesn't exists on the newsserver or doesn't contain the given
 * attachment.
 */
function message_read($id,$bodynum=0,$group="") {
  global $cache_articles,$spooldir,$text_error,$ns;
  if (!testGroup($group)) {
    echo $text_error["read_access_denied"];
    return;
  }
  $message = new messageType;
  if ((isset($cache_articles)) && ($cache_articles == true)) {
    // Try to load a cached article
    if ((ereg('^[0-9]+$',$id)) && ($group != ''))
      $filename=$group.'_'.$id;
    else
      $filename=base64_encode($id);
    $cachefilename_header=$spooldir."/".$filename.'.header';
    $cachefilename_body=$spooldir."/".$filename.'.body';
    if (file_exists($cachefilename_header)) {
      $cachefile=fopen($cachefilename_header,"r");
      $message->header=unserialize(fread($cachefile,filesize($cachefilename_header)));
      fclose($cachefile);
    } else {
      unset($message->header);
    }
    // Is a non-existing attachment of an article requested?
    if ((isset($message->header)) &&
        ($bodynum!= -1) &&
        (!isset($message->header->content_type[$bodynum])))
      return false;
    if ((file_exists($cachefilename_body.$bodynum)) &&
        ($bodynum != -1)) {
      $cachefile=fopen($cachefilename_body.$bodynum,"r");
      $message->body[$bodynum]=
        fread($cachefile,filesize($cachefilename_body.$bodynum));
      fclose($cachefile);
    }
  }
  if ((!isset($message->header)) ||
      ((!isset($message->body[$bodynum])) &&
       ($bodynum != -1))) {
    if (!isset($ns)) {
      $ns=nntp_open();
    }
    if ($group != "") {
      fputs($ns,"GROUP ".$group."\r\n");
      $line=line_read($ns);
    }
    fputs($ns,'ARTICLE '.$id."\r\n");
    $line=line_read($ns);
    if (substr($line,0,3) != "220") {
      // requested article doesn't exist on the newsserver. Now we
      // should check, if the thread stored in the spool-directory
      // also doesnt't contain that article...
      thread_cache_removearticle($group,$id);
      return false;
    }
    $rawmessage=array();
    $line=line_read($ns);
    while(strcmp($line,".") != 0) {
      $rawmessage[]=$line;
      $line=line_read($ns);
    }
    $message=message_parse($rawmessage);
    if (ereg('^[0-9]+$',$id)) $message->header->number=$id;
    // write header, body and attachments to the cache
    if ((isset($cache_articles)) && ($cache_articles == true)) {
      $cachefile=fopen($cachefilename_header,"w");
      if ($cachefile) {
        fputs($cachefile,serialize($message->header));
      }
      fclose($cachefile);
      for ($i=0; $i<count($message->header->content_type); $i++) {
        if (isset($message->body[$i])) {
          $cachefile=fopen($cachefilename_body.$i,"w");
          fwrite($cachefile,$message->body[$i]);
          fclose($cachefile);
        }
      }
    }
  }
  return $message;
}

function textwrap($text, $wrap=80, $break="\n"){
  $len = strlen($text);
  if ($len > $wrap) {
    $h = '';        // massaged text
    $lastWhite = 0; // position of last whitespace char
    $lastChar = 0;  // position of last char
    $lastBreak = 0; // position of last break
    // while there is text to process
    while ($lastChar < $len) {
      $char = substr($text, $lastChar, 1); // get the next character
      // if we are beyond the wrap boundry and there is a place to break
      if (($lastChar - $lastBreak > $wrap) && ($lastWhite > $lastBreak)) {
        $h .= substr($text, $lastBreak, ($lastWhite - $lastBreak)) . $break;
        $lastChar = $lastWhite + 1;
        $lastBreak = $lastChar;
      }
      // You may wish to include other characters as valid whitespace...
      if ($char == ' ' || $char == chr(13) || $char == chr(10)) {
        $lastWhite = $lastChar; // note the position of the last whitespace
      }
      $lastChar = $lastChar + 1; // advance the last character position by one
    }
    $h .= substr($text, $lastBreak); // build line
  } else {
    $h = $text; // in this case everything can fit on one line
  }
  return $h;
}
