home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 April / CMCD0404.ISO / Software / Freeware / Programare / groupoffice-com-2.01 / modules / news / nntp.class.inc < prev    next >
Text File  |  2004-03-08  |  28KB  |  630 lines

  1. <?php
  2. /*
  3.  * NNTP-Abstraction class
  4.  *
  5.  * Author: Markus Schabel <markus.schabel@tgm.ac.at>
  6.  * 
  7.  * TODO check if the calls of imap_*() have finished without problems and
  8.  * do something if an error  occoured.
  9.  * 
  10.  * TODO re-implement the postMessage function to use the imap functions
  11.  * and to return the message-id of the posted message so that we are able
  12.  * to display a thread if we just started one...
  13.  *
  14.  * TODO document nntp->postMessage() and the class nntpMessage
  15.  */
  16.  
  17. class nntpMessage {
  18.   // This variable is an array which stores the name and the email address
  19.   // of the sender of the message.
  20.   var $sender;
  21.   var $subject;
  22.   var $server;
  23.   var $groups;
  24.   var $id;
  25.   var $long_id;
  26.   var $timestamp;
  27.   var $lines;
  28.   var $references;
  29.   var $in_reply_to;
  30.   var $content;
  31.   var $body;
  32.  
  33.   var $answers;
  34.   var $depth;
  35.  
  36.   function nntpMessage( $nntp, $id ) {
  37.     $this->id = $id;
  38.     $head = imap_fetchheader( $nntp, $id, FT_UID|FT_PREFETCHTEXT );
  39.     if ( $head == "" ) {
  40.       // Message does not exist on the server!
  41.       $this = NULL;
  42.       return NULL;
  43.     }
  44.     $this->body = quoted_printable_decode( chop( imap_fetchbody( $nntp, $id, '1', FT_UID ) ) );
  45.     $head = str_replace( "\r\n ", "", $head );
  46.     $headers = explode( "\r\n", $head );
  47.     unset( $head );
  48.     foreach ( $headers as $header ) {
  49.       $headerinfo = explode( ": ", $header, 2 );
  50.       if ( count( $headerinfo ) == 2 ) {
  51.         if ( $headerinfo[0] == "From" ) {
  52.       $from = preg_split( "/[<@>]/", $headerinfo[1] );
  53.       if ( count( $from ) < 4 ) {
  54.         $this->sender["name"] = chop( $from[0] );
  55.         $this->sender["mail"] = $from[0]."@".$from[1];
  56.       } else {
  57.         $this->sender["name"] = chop( $from[0] );
  58.         $this->sender["mail"] = $from[1]."@".$from[2];
  59.       }
  60.         } else if ( $headerinfo[0] == "Xref" ) {
  61.       // This is usually "server group:id"
  62.       $xref = explode( " ", $headerinfo[1], 2 );
  63.       $this->server = $xref[0];
  64.       $xref = explode( " ", $xref[1] );
  65.       foreach ( $xref as $ref ) {
  66.         $group = explode( ":", $ref );
  67.         $this->groups[] = $group;
  68.       }
  69.         } else if ( $headerinfo[0] == "Subject" ) {
  70.           $this->subject = $headerinfo[1] ;
  71.         } else if ( $headerinfo[0] == "Date" ) {
  72.       $this->timestamp  = strtotime( $headerinfo[1] );
  73.         } else if ( $headerinfo[0] == "Lines" ) {
  74.       $this->lines = $headerinfo[1];
  75.     } else if ( $headerinfo[0] == "Message-ID" ) {
  76.       $this->long_id = $headerinfo[1];
  77.     } else if ( $headerinfo[0] == "References" ) {
  78.       $this->references = explode( " ", $headerinfo[1] );
  79.     } else if ( $headerinfo[0] == "In-Reply-To" ) {
  80.       $this->in_reply_to = split( " ", $headerinfo[1] );
  81.     } else if ( $headerinfo[0] == "Content-Type" ) {
  82.       $ctype = explode( "; ", $headerinfo[1] );
  83.       foreach ( $ctype as $detail ) {
  84.         if ( ( strpos( $detail, "charset=" ) === 0 ) ) {
  85.           $this->content["charset"] = substr( $detail, 8 );
  86.         } else if ( ( strpos( $detail, "format=" ) === 0 ) ) {
  87.           $this->content["format"] = substr( $detail, 7 );
  88.         } else {
  89.           $this->content["type"] = $detail;
  90.         }
  91.       }
  92.     } else if ( $headerinfo[0] == "Content-Transfer-Encoding" ) {
  93.       $this->content["transfer-encoding"] = $headerinfo[1];
  94.         } else if ( in_array( $headerinfo[0], array( "Path", "Newsgroups", "Organization", "NNTP-Posting-Host", "X-Trace", "X-Complaints-To", "NNTP-Posting-Date", "Mime-Version", "User-Agent", "X-Accept-Language" ) ) ) {
  95.       // IGNORE THESE
  96.     } else {
  97.           $head[$headerinfo[0]] = $headerinfo[1];
  98.     }
  99.       }
  100.     }
  101.     if ( isset( $this->content ) ) {
  102.       if ( isset( $this->content["charset"] ) ) {
  103.         $this->subject = utf8_decode( imap_utf8( $this->subject ) );
  104.       }
  105.     }
  106.   }
  107.  
  108.   function show( $mode='' ) {
  109.     echo "<table border='0' width='100%' cellspacing='0' cellpadding='1'";
  110.     echo " bgcolor='#000000'><tr><td>\n";
  111.     echo "<table border='0' width='100%' cellspacing='5' bgcolor='#FFFFFF'>";
  112.     echo "<tr><td>\n";
  113.     echo "<b><a href='".$_SERVER['PHP_SELF']."?task=show_groups&newsgroup=";
  114.     echo $this->groups[0][0]."'>".$this->groups[0][0]."</a>:  ";
  115.     echo $this->subject;
  116.     echo "</b>";
  117.     echo "<pre>";
  118.     echo htmlentities( $this->body );
  119.     echo "</pre>";
  120.     echo "<hr noshade size='1'>";
  121.     echo "<p align='center'>";
  122.     echo "Von <a href='mailto:".$this->sender["mail"]."'>";
  123.     echo $this->sender["name"]."</a>, ";
  124.     echo date("l dS of F Y H:i:s", $this->timestamp )."<br>";
  125.     echo " [ ";
  126.     if ( $mode == "comment" ) {
  127.       if ( $this->answers == 0 ) {
  128.         echo "0 Kommentare";
  129.       } else {
  130.         echo "<a href='".$_SERVER['PHP_SELF'];
  131.     echo "?task=show_thread&newsgroup=".$this->groups[0][0];
  132.     echo "&message=".$this->groups[0][1]."'>";
  133.         echo $this->answers." Kommentar";
  134.         if ( $this->answers != 1 ) {
  135.           echo "e";
  136.         }
  137.         echo "</a>";
  138.       }
  139.       echo " | ";
  140.     }
  141.     echo "<a href='".$_SERVER['PHP_SELF'];
  142.     echo "?task=answer_msgs&newsgroup=".$this->groups[0][0];
  143.     echo "&message=".$this->groups[0][1]."'>";
  144.     echo "Antworten";
  145.     echo "</a>";
  146.     echo " ] ";
  147.     echo "</p>";
  148.     echo "</td></tr></table>\n";
  149.     echo "</td></tr></table>\n";
  150.   }
  151.  
  152.   function cmp_timestamp( $a, $b ) {
  153.     if ( $a->timestamp == $b->timestamp ) return 0;
  154.     return ( $a->timestamp < $b->timestamp ) ? +1 : -1;
  155.   }
  156. }
  157.  
  158. class nntp {
  159.   // This variable stores the hostname of the server we are connecting
  160.   // to. It is set in the constructor.
  161.   var $host = "";
  162.   // This two variables store the account information we use to connect
  163.   // to the nntp server. They are set in the constructor.
  164.   var $user = "";
  165.   var $pass = "";
  166.   // Here we store our connection to the server. Since the actual version
  167.   // of PHP has no destructors we need to take care that our code closes
  168.   // the connection before exiting.
  169.   var $nntp = NULL;
  170.   // Here we store a list of all available groups. It is initialized when
  171.   // we open the connection to the server. It is an array of objects with
  172.   // the following attributes:
  173.   //   name       => contains the name of the group. This is an extended
  174.   //                 string, that means a lot of information we usually
  175.   //                 do not need: {hostname:port/nntp}group
  176.   //             eg. "{dot.tgm.ac.at:119/nntp}tgm.dot.bugs"
  177.   //   attributes =>
  178.   //             eg. int(0)
  179.   //   delimiter  =>
  180.   //             eg. "."
  181.   var $list = NULL;
  182.   // This variable contains the name of the group we're connected at the
  183.   // moment. So we do not need to rebind each time we fetch a message from
  184.   // the same group if we definitely know that we are already connected to
  185.   // this group.
  186.   var $group = NULL;
  187.  
  188.   // This is the constructor of this class. It initializes the variables
  189.   // that are used to connect to the server. The parameters user and pass
  190.   // are optional, since we are able to bind anonymously.
  191.   function nntp( $host, $user="", $pass="" ) {
  192.     // We just initialize the following variables and that's it.
  193.     $this->host = $host;
  194.     $this->user = $user;
  195.     $this->pass = $pass;
  196.   }
  197.  
  198.   // Open a connection to the server and get a list of available groups.
  199.   function open() {
  200.     // First we check if we already have an open connection. If we do not
  201.     // have we open a new one. With the current implementation it is not
  202.     // possible to access multiple servers at the same time with one object
  203.     // of this class, so we do not open a new connection if there still
  204.     // exists an open one.
  205.     if ( !$this->nntp ) {
  206.       // Ok, we have no open connections and are able to open a new one.
  207.       // As parameters we support the "imap"-string which represents our
  208.       // server. We also provide user and passwort. OP_HALFOPEN means that
  209.       // we open a connection but do not specify a group.
  210.       $this->nntp = @imap_open(
  211.                               "{".$this->host.":119/nntp}",
  212.                               $this->user, $this->pass,
  213.                               OP_HALFOPEN
  214.                               );
  215.       // Get a list of newsgroups from the server. As server we support
  216.       // the connection id we just got from imap_open. As reference we
  217.       // support the "root" of the server and as filter an asterix to get
  218.       // all available groups.
  219.       $this->list = @imap_getmailboxes(
  220.                                       $this->nntp,
  221.                                       "{".$this->host.":119/nntp}",
  222.                                       "*"
  223.                                       );
  224.       // Set the group we're connected to to NULL because we have no group
  225.       // selected at the moment.
  226.       $this->group = NULL;
  227.     }
  228.   }
  229.  
  230.   // Close the connection to the server.
  231.   function close() {
  232.     // First we check if there is an open connection. If we have one then
  233.     // we can close it. If we are not connected to a server we cannot
  234.     // close it ;)
  235.     if ( $this->nntp ) {
  236.       // We found a connection so we can close it.
  237.       @imap_close( $this->nntp );
  238.     }
  239.     // Reset the connection variable.
  240.     $this->nntp = NULL;
  241.   }
  242.  
  243.   // Return a list of all avaliable groups.
  244.   function getGroups() {
  245.     // We only can return a list of groups if we are connected to the
  246.     // server. So check if there is an open connection...
  247.     if ( $this->nntp ) {
  248.       // There's an open connection so we can return the list of groups
  249.       // the server has. This list is queried when we open the connection
  250.       // to the server.
  251.       return $this->list;
  252.     } else {
  253.       // If there is no connection we have no groups and return false.
  254.       return false;
  255.     }
  256.   }
  257.  
  258.   // Try to find out the full name of the group (that means with the
  259.   // server the port and so on, this is needed each time we reopen the
  260.   // connection to a specific group.
  261.   function getFullNameOfGroup( $fromgroup ) {
  262.     // First we check if we have an open connection. No need to do
  263.     // something if we have no connections opened.
  264.     if ( $this->nntp ) {
  265.       // Ok, there is an open connection.
  266.       // We need to find out the complete name of the group we got as
  267.       // parameter. So we proceed for each entry in the list of all groups
  268.       // and compare each one with the name we got as parameter.
  269.       foreach ( $this->list as $ng ) {
  270.         // We split the complex name ({dot.tgm.ac.at:119/nntp}tgm.dot.bugs)
  271.     // into a simpler array with the following regular expression: {}:/
  272.     // so we get the following seperate values in our array:
  273.     //   [1] => dot.tgm.ac.at
  274.     //   [2] => 119
  275.     //   [3] => nntp
  276.     //   [4] => tgm.dot.bugs
  277.         $group = preg_split ("/[{}:\/]+/", $ng->name );
  278.     // Now we compare if the group we got as parameter is the same as
  279.     // the last part of the complex name in our list.
  280.         if ( $fromgroup == $group[4] ) {
  281.       // It is the same, so we initialize the variable ngroup with the
  282.       // full name. It is needed again when we re-open our connection.
  283.           return $ng;
  284.         }
  285.       }
  286.     }
  287.     // If we reach this point, we have not found the group we were searching
  288.     // for and can indicate that the search failed.
  289.     return false;
  290.   }
  291.  
  292.   // Get a message from a group. As parameters the group and the message
  293.   // id must be supported.
  294.   function getMessage( $fromgroup, $num ) {
  295.     if ( $this->nntp ) {
  296.       // Find out what the long identifier of this group is, that means the
  297.       // long string that is needed to open/reopen a connection to the server.
  298.       $ngroup = $this->getFullNameOfGroup( $fromgroup );
  299.       // If we were able to find out to which group the message belongs, then
  300.       // we can fetch all interesting data of this msg.
  301.       if ( $ngroup ) {
  302.         // We check if we are connected to the correct group, and if not we
  303.         // reconnect to the right one.
  304.         if ( $this->group != $ngroup->name ) {
  305.           // We reopen the connection, and connect to the correct group.
  306.           @imap_reopen( $this->nntp, $ngroup->name );
  307.           // Now we set the group we are connected to to this one.
  308.           $this->group = $ngroup->name;
  309.         }
  310.         // Query the server for this message and return it to the calling
  311.         // function. This will generate a new object with all data of the
  312.         // message in it, and is therefore a standardized way to represent
  313.         // our messages.
  314.         return new nntpMessage( $this->nntp, $num );
  315.       }
  316.     }
  317.     // We only reach this point if we have not found message before, that
  318.     // means we have not found the corresponding group or have no open
  319.     // connection to the server. So we inform the caller that we failed.
  320.     return false;
  321.   }
  322.  
  323.   // This is a slightly more complex function which queries all messages
  324.   // from the supplied groups. If we do not supply a list of groups this
  325.   // function will return all messages of all available groups.
  326.   function getMessages( $fromgroups='', $sort=1 ) {
  327.     if ( $this->nntp ) {
  328.       $thread_arr = array();
  329.       $thread_dep = 0;
  330.  
  331.       // For all groups we try to find out if we should query the group.
  332.       foreach ( $this->list as $ng ) {
  333.         // The same as in the function getMessage, we split the name of
  334.         // the group into something we can easily read.
  335.         $group = preg_split ("/[{}:\/]+/", $ng->name );
  336.         // First we think that the current processed will not be processed
  337.         // and then we check if we have to.
  338.         $process = false;
  339.         // If we have no list of groups as parameter we have to process all
  340.         // groups.
  341.         if ( $fromgroups == '' ) {
  342.           // Ok, we process all groups, so we set the variable to true.
  343.           $process = true;
  344.         } else {
  345.           // We got something as parameter and we need to check if it is an
  346.           // array (a list of groups) or a string (a single group).
  347.           if ( is_array( $fromgroups ) ) {
  348.             // We have an array as parameter. So we have to check if the
  349.             // current processed newsgroup is an element of the array. If it
  350.             // is we should process this group.
  351.             if ( in_array( $group[4], $fromgroups ) ) {
  352.               // It is element of the array, so we process this group.
  353.               $process = true;
  354.             }
  355.           } else {
  356.             // The parameter is no array. So it must be a string and we
  357.             // compare the parameter and the actual group.
  358.             if ( $fromgroups == $group[4] ) {
  359.               // They are the same, so we process this group.
  360.               $process = true;
  361.             }
  362.           }
  363.         }
  364.         // We checked all possibilities if we have to process the group
  365.         // or not. If we need to process it, then we do it now.
  366.         if ( $process ) {
  367.           // First we reopen the connection to bind to the specific group
  368.           // we are processing at the moment. We don't check if we are
  369.           // already connected to this group, because most times this code
  370.           // runs it will have to rebind since this function usually
  371.           // processes more than one group.
  372.           imap_reopen( $this->nntp, $ng->name );
  373.           // We connected to a specific group, so we can set the status
  374.           // variable to this group. We could also do this at the end of this
  375.           // function, but it doesn't need much processing time, and setting
  376.           // the variable each time we change our selected group is the clean
  377.           // way.
  378.           $this->group = $ng->name;
  379.           // We check if there are postings in this group available. If there
  380.           // are no postings, it is not needed to process this group.
  381.           // Check if there is at least one message available.
  382.           if ( imap_num_msg( $this->nntp ) > 0 ) {
  383.             // There are messages on the server in this group available.
  384.             // Get all headers of this group. With the current implementation
  385.             // of the imap functions in PHP it is not possible to get only
  386.             // some messages, it will always return _all_ messages!
  387.             $headers = @imap_headers( $this->nntp );
  388.             // Get the threads of the current group. This returns a somewhat
  389.             // strange array. Since this function is not documented at the
  390.             // moment it was complicated to find out what it really does...
  391.             // The index of the array is always a string that consists of two
  392.             // parts seperated by a dot: the fist part is an integer that is
  393.             // only used to group the second part to messages, we can ignore
  394.             // it at the moment (and probably at any time). The second part
  395.             // is one of the following strings: num, next and branch.
  396.             // We can ignore "next", this should be the next message in the
  397.             // thread, but I'm not sure of that. If it is "num" it indicates
  398.             // that have to move a level deeper in the thread, and if it is
  399.             // "branch" we go up one level again. Each time "branch" is set,
  400.             // "next" should be 0, but I'm really not sure of thet.
  401.             // The second part of the array (the value) contains the mesg-id
  402.             // of that message. In fact this is the number we're using to
  403.             // fetch the message from the server.
  404.             // The following is a short example of the return value of this
  405.             // function:
  406.             // array(18) {
  407.             //  ["0.num"]    => int(1)
  408.             //  ["0.next"]   => int(1)
  409.             //  ["1.num"]    => int(2)    o 1
  410.             //  ["1.next"]   => int(0)    |--o 2 
  411.             //  ["1.branch"] => int(2)    |--o 3
  412.             //  ["2.num"]    => int(3)       |--o 4
  413.             //  ["2.next"]   => int(3)          |--o 5
  414.             //  ["3.num"]    => int(4)          |--o 6
  415.             //  ["3.next"]   => int(4)
  416.             //  ["4.num"]    => int(5)
  417.             //  ["4.next"]   => int(0)
  418.             //  ["4.branch"] => int(5)
  419.             //  ["5.num"]    => int(6)
  420.             //  ["5.next"]   => int(0)
  421.             //  ["5.branch"] => int(0)
  422.             //  ["3.branch"] => int(0)
  423.             //  ["2.branch"] => int(0)
  424.             //  ["0.branch"] => int(0)
  425.             // }
  426.             $threads = @imap_thread( $this->nntp, SE_UID );
  427.             // For each entry of the array we got from imap_threads we split
  428.             // it into a key and a value pair (the key is the index in the
  429.             // array and the value is the value of that element in the array).
  430.             // The key is the identifier of the depth in the thread and the
  431.             // value is the message id.
  432.             while ( list( $key, $val ) = each( $threads ) ) {
  433.               // We split the current index into a new array. The first value
  434.               // contains an id and the second tells us what we need to do: If
  435.               // it is "num" then we increment the thread_depth (which means
  436.               // we leave the root of the thread and process to answers in the
  437.               // thread. And if it is "branch" we decrement thread_depth which
  438.               // means we tend to the root of the thread.
  439.               $tree = explode( ".", $key );
  440.               // Now we do this.
  441.               if ( $tree[1] == "num" ) {
  442.                 // If the depth in the thread is zero we have a new thread.
  443.                 if ( $thread_dep == 0 ) {
  444.                   // Since this is a new thread there are no answers now. This
  445.                   // variable is used to store the number of answers in this
  446.                   // thread.
  447.                   $thread_num = 0;
  448.                   // Fetch the current message from the server.
  449.                   $message = new nntpMessage( $this->nntp, $val );
  450.                 } else {
  451.                   // We already are in a thread, so we increment the number of
  452.                   // messages that are in this thread.
  453.                   $thread_num++;
  454.                 }
  455. //              if ( $message )
  456.                   $thread_dep++;
  457.               // Now we have a branch, that means the current thread (to be
  458.               // exact the actual subtree of this thread) ends here. So we
  459.               // decrement the depth in this thread and if it reaches 0 we 
  460.               // can say that this thread is finished.
  461.               } else if ($tree[1] == "branch") {
  462.                 // As we said before, we decrement the depth in this thread.
  463.                 $thread_dep--;
  464.                 // Now we check if we already reached the top-level (that
  465.                 // means this thread ends here).
  466.                 if ( $thread_dep == 0 ) {
  467.                   // Check if the message exists. If the message is deleted
  468.                   // from the server, this variable will be NULL.
  469.                   if ( $message ) {
  470.                     // $message is the first message of this thread. We now
  471.                     // know the number of answers to this message and set the
  472.                     // corresponding attribute.
  473.                     $message->answers = $thread_num;
  474.                     // Append the message to the array of all messages.
  475.                     $thread_arr[] = $message;
  476.                     // unset message, so it really will be NULL if the next
  477.                     // message we fetch from the server is deleted.
  478.                     unset( $message );
  479.                   }
  480.                 }
  481.               // We can ignore all other cases (e.g. "next").
  482.               }
  483.             }
  484.           }
  485.         }
  486.       }
  487.       // If we should sort the messages, then do it.
  488.       if ( $sort == 1 ) {
  489.         // The class nntpMessage has a function (cmp_timestamp()) that
  490.         // compares the timestamps of two messages.
  491.         usort( $thread_arr, array( "nntpMessage", "cmp_timestamp" ) );
  492.       }
  493.       // Return the list of messages we fetched.
  494.       return $thread_arr;
  495.     }
  496.     // We only reach this point if there is no connection to the server
  497.     // available. So we indicate that we weren't able to process the
  498.     // request.
  499.     return false;
  500.   }
  501.  
  502.   function getThread( $fromgroup, $message ) {
  503.     // First we have to check if we are connected to the server. We can just
  504.     // fail if we are not connected.
  505.     if ( $this->nntp ) {
  506.       // Find out what the long identifier of this group is, that means the
  507.       // long string that is needed to open/reopen a connection to the server.
  508.       $ngroup = $this->getFullNameOfGroup( $fromgroup );
  509.       // If we were able to find out the exact name of the group we are
  510.       // searching for, we can proceed.
  511.       if ( $ngroup ) {
  512.         // Now we find out if we are already connected to this group, and if
  513.         // not we connect to it.
  514.         if ( $this->group != $ngroup->name ) {
  515.           // We reconnect to this specific group.
  516.           imap_reopen( $this->nntp, $ngroup->name );
  517.           // And set our status variable to this group.
  518.           $this->group = $ngroup->name;
  519.         }
  520.         // We are now definitly connected to the correct group.
  521.         // Now we find out how many messages are in this group. If there are
  522.         // no messages posted, we do not need to get the thread ;-)
  523.         if ( imap_num_msg( $this->nntp ) > 0 ) {
  524.           // Since there are messages in this group, we get the thread
  525.           // information from this server. The syntax of the array this
  526.           // function returns is explained in the corresponding code fragment
  527.           // of the function getMessages().
  528.           $threads = @imap_thread($this->nntp, SE_UID);
  529.           // We do not know in which thread our message id is, so we have to
  530.           // process all available threads till we find our message. At the
  531.           // beginning we can say that we haven't found it.
  532.           $found = false;
  533.           // We are at the top-level of the messages in the group, that means
  534.           // we are flat and not in any thrad.
  535.           $thread_dep = 0;
  536.           // A thread is an array of messages. To use the function [] of this
  537.           // array we have to say PHP that it is an array.
  538.           $thread = array();
  539.           // Process each entry we got from imap_threads(). What we are doing
  540.           // here is also explaind in the code of getMessages().
  541.           while ( list( $key, $val ) = each( $threads ) ) {
  542.             // We split the current index in the array into two parts, the
  543.             // first part is the id (for internal use only, we can ignore it)
  544.             // and the second part tells us what we have to do. "num" is a
  545.             // message in a thread, so we have to increase the depth, and
  546.             // branch is the end of a thread so we have to decrease depth.
  547.             $tree = explode(".", $key);
  548.             // Do it. If it is num we have to increase the depth.
  549.             if ($tree[1] == "num") {
  550.               // First we check if we found our message and set the variable
  551.               // to exit after when we processed the complete thread.
  552.               if ( $val == $message )
  553.             $found = true;
  554.               // We've said we have to increase the depth in the thread.
  555.           $thread_dep++;
  556.               // Now get the message from the server. This is standardized to
  557.               // simplify adding new features.
  558.               $message = new nntpMessage( $this->nntp, $val );
  559.               // Tell the message in which depth in the thread we found it.
  560.               // This is needed for a correct threaded display.
  561.           $message->depth = $thread_dep;
  562.               // Add this message to the thread.
  563.           $thread[] = $message;
  564.             // If the second part of the result from imap_thread() is "branch"
  565.             // then we go a level lower, that means decrease depth.
  566.             } else if ($tree[1] == "branch") {
  567.               // Decrease depth.
  568.               $thread_dep--;
  569.               // If we are at top-level again, we have finished this thread.
  570.               if ( $thread_dep == 0 ) {
  571.                 // Now we have two possibilities: if we found the message,
  572.                 // then we can return the thread.
  573.             if ( $found ) {
  574.                   return $thread;
  575.                 // and if we haven't found the message yet, we can reset
  576.                 // the thread and process with the next.
  577.                 } else {
  578.                   $thread = array();
  579.                 }
  580.               }
  581.         }
  582.       }
  583.     }
  584.       }
  585.     }
  586.     // If we haven't returned till now, we haven't found the thread and can
  587.     // exit with an error.
  588.     return false;
  589.   }
  590.  
  591.   function postMessage( $togroup, $sender, $references, $subject, $message ) {
  592.     if ( !$stream = fsockopen("dot.tgm.ac.at",119,$errno,$errstr) ) {
  593.       echo "server:".$errstr."($errno)<br>\n";
  594.     }
  595.     // This should be "200 dot.tgm.ac.at InterNetNews NNRP server INN 2.4.0 ready (posting ok)."
  596.     $answer = fgets($stream);
  597.     fwrite($stream, "post\r\n");
  598.     // This should be "340 Ok, recommended ID"
  599.     $answer = fgets($stream);
  600.     fwrite($stream, "From: ".$sender."\r\n");
  601.     fwrite($stream, "Subject: ".$subject."\r\n");
  602.     fwrite($stream, "Newsgroups: ".$togroup."\r\n");
  603.     fwrite($stream, "References: ".$references."\r\n");
  604.     fwrite($stream, "In-Reply-To: ".$references."\r\n");
  605.     fwrite($stream, "\r\n");
  606.  
  607.     if (!strstr("\n", "\r"))
  608.       $text = str_replace("\r", '', $message);
  609.     $lines = explode( "\n", $text );
  610.     echo "<pre>";
  611.     foreach ( $lines as $key => $line ) {
  612.       $line = wordwrap( $line );
  613.       fwrite($stream, $line."\r\n");
  614.     }
  615.     echo "</pre>";
  616.     fwrite($stream, "\n.\n");
  617.     // This should be "240 Article posted <ID>"
  618.     $answer = fgets($stream)."<br>";
  619.     fclose($stream);
  620.  
  621.     if ( substr( $answer, 0, 3 ) == "240" ) {
  622.       // We need to get the message id out of this string.
  623.       return true;
  624.     } else {
  625.       return false;
  626.     }
  627.   }
  628. }
  629. ?>
  630.