ekiga r6344 - in trunk: . src/endpoints



Author: dsandras
Date: Mon Jun  2 19:40:49 2008
New Revision: 6344
URL: http://svn.gnome.org/viewvc/ekiga?rev=6344&view=rev

Log:
Converted the H323 EndPoint into a PresentityDecorator, ContactDecorator 
and CallProtocolManager.


Modified:
   trunk/ChangeLog
   trunk/src/endpoints/h323.cpp
   trunk/src/endpoints/h323.h
   trunk/src/endpoints/manager.cpp
   trunk/src/endpoints/opal-main.cpp
   trunk/src/endpoints/sip.cpp
   trunk/src/endpoints/sip.h

Modified: trunk/src/endpoints/h323.cpp
==============================================================================
--- trunk/src/endpoints/h323.cpp	(original)
+++ trunk/src/endpoints/h323.cpp	Mon Jun  2 19:40:49 2008
@@ -39,50 +39,56 @@
 #include "config.h"
 
 #include "h323.h"
-#include "ekiga.h"
-#include "pcss.h"
 
-#include "misc.h"
+#include "opal-call.h"
 
-#include "gmconf.h"
-#include "gmdialog.h"
 
-#include <opal/transcoders.h>
+class dialer : public PThread
+{
+  PCLASSINFO(dialer, PThread);
 
+public:
 
-#define new PNEW
+  dialer (const std::string & uri, GMManager & ep) 
+    : PThread (1000, AutoDeleteThread), 
+      dial_uri (uri),
+      endpoint (ep) 
+  {
+    this->Resume ();
+  };
+  
+  void Main () 
+  {
+    PString token;
+    endpoint.SetUpCall ("pc:*", dial_uri, token);
+  };
+
+private:
+  const std::string dial_uri;
+  GMManager & endpoint;
+};
 
 
 /* The class */
-GMH323Endpoint::GMH323Endpoint (GMManager & ep, Ekiga::ServiceCore & _core)
+GMH323Endpoint::GMH323Endpoint (GMManager & ep, Ekiga::ServiceCore & _core, unsigned _listen_port)
 : H323EndPoint (ep), 
   endpoint (ep),
   core (_core),
   runtime (*(dynamic_cast<Ekiga::Runtime *> (core.get ("runtime"))))
 {
-  udp_min = 5000;
-  udp_max = 5100; 
-  tcp_min = 30000;
-  tcp_max = 30010; 
-  listen_port = 1720;
-
-  SetInitialBandwidth (40000);
-
-  uri_prefix = "h323:";
   protocol_name = "h323";
+  uri_prefix = "h323:";
+  listen_port = _listen_port;
 
-  start_listening ();
-}
-
-const std::string & GMH323Endpoint::get_protocol_name () const
-{
-  return protocol_name;
-}
-
+  /* Initial requested bandwidth */
+  SetInitialBandwidth (40000);
+  
+  /* Start listener */
+  set_listen_port (listen_port);
 
-const Ekiga::CallProtocolManager::Interface & GMH323Endpoint::get_interface () const
-{
-  return interface;
+  /* Ready to take calls */
+  endpoint.AddRouteEntry("h323:.* = pc:<db>");
+  endpoint.AddRouteEntry("pc:.* = h323:<da>");
 }
 
 
@@ -107,8 +113,8 @@
 
 
 bool GMH323Endpoint::menu_builder_add_actions (const std::string & /*fullname*/,
-                                               std::map<std::string,std::string> & uris,
-                                               Ekiga::MenuBuilder & builder)
+                                              std::map<std::string,std::string> & uris,
+                                              Ekiga::MenuBuilder & builder)
 {
   bool populated = false;
 
@@ -131,13 +137,30 @@
 }
 
 
-void
-GMH323Endpoint::SetUserInputMode ()
+bool GMH323Endpoint::dial (const std::string & uri)
 {
-  int mode = 0;
+  PString token;
+  std::stringstream ustr;
+
+  if (uri.find ("h323:") == 0) {
+
+    new dialer (ustr.str (), endpoint);
+
+    return true;
+  }
+
+  return false;
+}
 
-  mode = gm_conf_get_int (H323_KEY "dtmf_mode");
 
+const std::string & GMH323Endpoint::get_protocol_name () const
+{
+  return protocol_name;
+}
+
+
+void GMH323Endpoint::set_dtmf_mode (unsigned mode)
+{
   switch (mode) 
     {
     case 0:
@@ -158,6 +181,64 @@
 }
 
 
+unsigned GMH323Endpoint::get_dtmf_mode () const
+{
+  if (GetSendUserInputMode () == OpalConnection::SendUserInputAsString)
+    return 0;
+
+  if (GetSendUserInputMode () == OpalConnection::SendUserInputAsTone)
+    return 1;
+
+  if (GetSendUserInputMode () == OpalConnection::SendUserInputAsInlineRFC2833)
+    return 2;
+
+  if (GetSendUserInputMode () == OpalConnection::SendUserInputAsQ931)
+    return 2;
+
+  return 1;
+}
+
+
+bool GMH323Endpoint::set_listen_port (unsigned port)
+{
+  interface.protocol = "tcp";
+  interface.interface = "*";
+
+  if (port > 0) {
+
+    std::stringstream str;
+    RemoveListener (NULL);
+
+    str << "tcp$*:" << port;
+    if (StartListeners (PStringArray (str.str ()))) {
+
+      interface.port = port;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+const Ekiga::CallProtocolManager::Interface & GMH323Endpoint::get_listen_interface () const
+{
+  return interface;
+}
+
+
+void GMH323Endpoint::set_forward_uri (const std::string & uri)
+{
+  forward_uri = uri;
+}
+
+
+const std::string & GMH323Endpoint::get_forward_uri () const
+{
+  return forward_uri;
+}
+
+
 void
 GMH323Endpoint::Register (const PString & aor,
                           const PString & authUserName,
@@ -183,12 +264,11 @@
     H323EndPoint::RemoveGatekeeper (0);
 
     /* Signal */
-    /*
-    runtime.run_in_main (sigc::bind (registration_event.make_slot (), 
+    runtime.run_in_main (sigc::bind (endpoint.registration_event.make_slot (), 
                                      aor,
                                      Ekiga::CallCore::Processing,
                                      std::string ()));
-*/ //TODO
+
     if (!authUserName.IsEmpty ()) {
       SetLocalUserName (authUserName);
       AddAliasName (endpoint.GetDefaultDisplayName ());
@@ -232,23 +312,18 @@
       else
 	info = _("Failed");
 
-      /* Signal */
-      /*
-      runtime.run_in_main (sigc::bind (registration_event.make_slot (), 
+      runtime.run_in_main (sigc::bind (endpoint.registration_event.make_slot (), 
                                        aor, 
                                        Ekiga::CallCore::RegistrationFailed,
                                        info));
-                                       */
     }
     else {
 
       /* Signal */
-      /*
-      runtime.run_in_main (sigc::bind (registration_event.make_slot (), 
+      runtime.run_in_main (sigc::bind (endpoint.registration_event.make_slot (), 
                                        aor,
                                        Ekiga::CallCore::Registered,
                                        std::string ()));
-                                       */
     }
   }
   else if (unregister && IsRegisteredWithGatekeeper (host)) {
@@ -257,12 +332,10 @@
     RemoveAliasName (authUserName);
 
     /* Signal */
-    /*
-    runtime.run_in_main (sigc::bind (registration_event.make_slot (), 
+    runtime.run_in_main (sigc::bind (endpoint.registration_event.make_slot (), 
                                      aor,
                                      Ekiga::CallCore::Unregistered,
                                      std::string ()));
-                                     */
   }
 }
 
@@ -302,145 +375,37 @@
 }
 
 
-H323Connection *GMH323Endpoint::CreateConnection (OpalCall & _call,
-                                                  const PString & token,
-                                                  void *userData,
-                                                  OpalTransport & transport,
-                                                  const PString & alias,
-                                                  const H323TransportAddress & address,
-                                                  H323SignalPDU *setupPDU,
-                                                  unsigned options,
-                                                  OpalConnection::StringOptions *stringOptions)
-{
-  /* FIXME
-  Ekiga::Call *call = dynamic_cast<Ekiga::Call *> (&_call);
-  Ekiga::CallCore *call_core = dynamic_cast<Ekiga::CallCore *> (core.get ("call-core"));
-  if (call_core)
-    call_core->add_call (call, this);
-    */
-
-  return H323EndPoint::CreateConnection (_call, token, userData, transport, alias, address, setupPDU, options, stringOptions);
-}
-
-
 bool 
-GMH323Endpoint::OnIncomingConnection (OpalConnection & /*connection*/,
+GMH323Endpoint::OnIncomingConnection (OpalConnection & connection,
                                       G_GNUC_UNUSED unsigned options,
-                                      G_GNUC_UNUSED OpalConnection::StringOptions *str_options)
+                                      G_GNUC_UNUSED OpalConnection::StringOptions *stroptions)
 {
   PTRACE (3, "GMH323Endpoint\tIncoming connection");
 
-  /*
-  if (!forward_uri.empty () && unconditional_forward)
+  if (!forward_uri.empty () && endpoint.get_unconditional_forward ())
     connection.ForwardCall (forward_uri);
-  else if (endpoint.GetCallsNumber () >= 1) { 
+  else if (endpoint.GetCallsNumber () > 1) { 
 
-    if (!forward_uri.empty () && forward_on_busy)
+    if (!forward_uri.empty () && endpoint.get_forward_on_busy ())
       connection.ForwardCall (forward_uri);
-    else 
+    else {
       connection.ClearCall (OpalConnection::EndedByLocalBusy);
+    }
   }
-  else
-    return H323EndPoint::OnIncomingConnection (connection, options, stroptions);
-    */ //TODO
-
-  return false;
-}
-
-
-void 
-GMH323Endpoint::OnRegistrationConfirm ()
-{
-  H323EndPoint::OnRegistrationConfirm ();
-}
-
-  
-void 
-GMH323Endpoint::OnRegistrationReject ()
-{
-  PWaitAndSignal m(gk_name_mutex);
-
-  gk_name = PString::Empty ();
-
-  H323EndPoint::OnRegistrationReject ();
-}
-
-
-void 
-GMH323Endpoint::OnEstablished (OpalConnection &connection)
-{
-  PTRACE (3, "GMSIPEndpoint\t H.323 connection established");
-  H323EndPoint::OnEstablished (connection);
-}
-
-
-void 
-GMH323Endpoint::OnReleased (OpalConnection &connection)
-{
-  PTRACE (3, "GMSIPEndpoint\t H.323 connection released");
-  H323EndPoint::OnReleased (connection);
-}
-
-
-bool GMH323Endpoint::start_listening ()
-{
-  std::stringstream str;
-  RemoveListener (NULL);
-
-  interface.publish = false;
-  interface.voip_protocol = protocol_name;
-  interface.protocol = "tcp";
-  interface.interface = "*";
-
-  str << "tcp$*:" << listen_port;
-  if (StartListeners (PStringArray (str.str ().c_str ()))) {
-    interface.port = listen_port;
-    return true;
-  }
-
-  return false;
-}
-
-
-bool GMH323Endpoint::set_tcp_ports (const unsigned min, const unsigned max) 
-{
-  if (min > 0 && max > 0 && min < max) {
-
-    tcp_min = min;
-    tcp_max = max;
-    endpoint.SetTCPPorts (tcp_min, tcp_max);
-
-    return true;
-  }
-
-  return false;
-}
-
-
-bool GMH323Endpoint::set_udp_ports (const unsigned min, const unsigned max) 
-{
-  if (min > 0 && max > 0 && min + 12 < max) {
-
-    udp_min = min;
-    udp_max = max;
-    endpoint.SetRtpIpPorts (udp_min, udp_max);
-    endpoint.SetUDPPorts (udp_min, udp_max);
-
-    return true;
-  }
+  else {
 
-  return false;
-}
+      Opal::Call *call = dynamic_cast<Opal::Call *> (&connection.GetCall ());
+      if (call) {
 
+        if (!forward_uri.empty () && endpoint.get_forward_on_no_answer ()) 
+          call->set_no_answer_forward (endpoint.get_reject_delay (), forward_uri);
+        else
+          call->set_reject_delay (endpoint.get_reject_delay ());
+      }
 
-bool GMH323Endpoint::set_listen_port (const unsigned listen)
-{
-  if (listen > 0) {
-
-    listen_port = listen;
-    return start_listening ();
+    return H323EndPoint::OnIncomingConnection (connection, options, stroptions);
   }
-
+  
   return false;
 }
 

Modified: trunk/src/endpoints/h323.h
==============================================================================
--- trunk/src/endpoints/h323.h	(original)
+++ trunk/src/endpoints/h323.h	Mon Jun  2 19:40:49 2008
@@ -48,25 +48,20 @@
 
 
 /* Minimal H.323 endpoint implementation */
-class GMH323Endpoint : public H323EndPoint
+class GMH323Endpoint : 
+    public H323EndPoint,
+    public Ekiga::CallProtocolManager,
+    public Ekiga::PresentityDecorator,
+    public Ekiga::ContactDecorator
 {
   PCLASSINFO(GMH323Endpoint, H323EndPoint);
 
  public:
 
-  /* DESCRIPTION  :  The constructor.
-   * BEHAVIOR     :  Creates the H.323 Endpoint 
-   * 		     and initialises the variables
-   * PRE          :  /
-   */
-  GMH323Endpoint (GMManager &ep, Ekiga::ServiceCore & core);
+  GMH323Endpoint (GMManager &ep, Ekiga::ServiceCore & core, unsigned listen_port);
 
-  /**/
-  const std::string & get_protocol_name () const;
-
-  const Ekiga::CallProtocolManager::Interface & get_interface () const;
 
-  /**/
+  /* ContactDecorator and PresentityDecorator */
   bool populate_menu (Ekiga::Contact &contact,
                       Ekiga::MenuBuilder &builder);
 
@@ -77,19 +72,25 @@
                                  std::map<std::string, std::string> & uris,
                                  Ekiga::MenuBuilder & builder);
 
-  /* DESCRIPTION  :  /
-   * BEHAVIOR     :  Adds the User Input Mode following the
-   *                 configuration options. String, Tone, and RFC2833 are 
-   *                 supported for now.
-   * PRE          :  /
-   */
-  void SetUserInputMode ();
-  
 
-  /* DESCRIPTION  :  /
-   * BEHAVIOR     :  Register the H323 endpoint to the given H323 server. 
-   * PRE          :  Correct parameters.
-   */
+  /* CallProtocolManager */
+  bool dial (const std::string & uri); 
+
+  const std::string & get_protocol_name () const;
+
+  void set_dtmf_mode (unsigned mode);
+  unsigned get_dtmf_mode () const;
+
+  bool set_listen_port (unsigned port);
+  const Ekiga::CallProtocolManager::Interface & get_listen_interface () const;
+
+
+  /* H.323 CallProtocolManager */
+  void set_forward_uri (const std::string & uri);
+  const std::string & get_forward_uri () const;
+
+
+  /* OPAL methods */
   void Register (const PString & aor,
                  const PString & authUserName,
                  const PString & password,
@@ -97,93 +98,19 @@
                  unsigned int expires,
                  bool unregister);
 
-  
-  /* DESCRIPTION  :  /
-   * BEHAVIOR     :  Use the given gatekeeper.
-   * PRE          :  /
-   */
   bool UseGatekeeper (const PString & address = PString::Empty (),
 		      const PString & domain = PString::Empty (),
 		      const PString & iface = PString::Empty ());
   
-
-  /* DESCRIPTION  :  /
-   * BEHAVIOR     :  Remove the given gatekeeper if we were registered to it.
-   * 		     Returns TRUE if it worked.
-   * PRE          :  Non-Empty address.
-   */
   bool RemoveGatekeeper (const PString & address);
   
-  
-  /* DESCRIPTION  :  /
-   * BEHAVIOR     :  Returns TRUE if we are registered with 
-   * 		     the given gatekeeper.
-   * PRE          :  Non-Empty address.
-   */
   bool IsRegisteredWithGatekeeper (const PString & address);
   
-
-  H323Connection *CreateConnection (OpalCall & call,
-                                    const PString & token,
-                                    void * userData,
-                                    OpalTransport & transport,
-                                    const PString & alias,
-                                    const H323TransportAddress & address,
-                                    H323SignalPDU *setupPDU,
-                                    unsigned int options = 0,
-                                    OpalConnection::StringOptions * stringOptions = NULL); 
-
-
-  /* DESCRIPTION  :  Called when there is an incoming SIP connection.
-   * BEHAVIOR     :  Checks if the connection must be rejected or forwarded
-   * 		     and call the manager function of the same name
-   * 		     to update the GUI and take the appropriate action
-   * 		     on the connection. If the connection is not forwarded,
-   * 		     or rejected, OnShowIncoming will be called on the PCSS
-   * 		     endpoint, allowing to auto-answer the call or do further
-   * 		     updates of the GUI and internal timers.
-   * PRE          :  /
-   */
   bool OnIncomingConnection (OpalConnection &connection,
                              unsigned options,
                              OpalConnection::StringOptions *str_options);
 
 
-  /* DESCRIPTION  :  Called when the gatekeeper accepts the registration.
-   * BEHAVIOR     :  Update the endpoint state.
-   * PRE          :  /
-   */
-  void OnRegistrationConfirm ();
-
-  
-  /* DESCRIPTION  :  Called when the gatekeeper rejects the registration.
-   * BEHAVIOR     :  Update the endpoint state.
-   * PRE          :  /
-   */
-  void OnRegistrationReject ();
-
-  
-  /* DESCRIPTION  :  This callback is called when the connection is 
-   *                 established and everything is ok.
-   * BEHAVIOR     :  Stops the timers.
-   * PRE          :  /
-   */
-  void OnEstablished (OpalConnection &);
-
-  
-  /* DESCRIPTION  :  This callback is called when a connection to a remote
-   *                 endpoint is cleared.
-   * BEHAVIOR     :  Stops the timers.
-   * PRE          :  /
-   */
-  void OnReleased (OpalConnection &);
-
-  bool start_listening ();
-  bool set_udp_ports (const unsigned min, const unsigned max);
-  bool set_tcp_ports (const unsigned min, const unsigned max);
-  bool set_listen_port (const unsigned listen);
-
-
  private:
   void on_dial (std::string uri);
 
@@ -194,17 +121,13 @@
   PMutex gk_name_mutex;
   PString gk_name;
 
-  std::string forward_uri;
-  unsigned tcp_min;
-  unsigned tcp_max;
-  unsigned udp_min;
-  unsigned udp_max;
-  unsigned listen_port;
-
   Ekiga::CallProtocolManager::Interface interface;
 
   std::string protocol_name;
   std::string uri_prefix;
+  std::string forward_uri;
+
+  unsigned listen_port;
 };
 
 #endif

Modified: trunk/src/endpoints/manager.cpp
==============================================================================
--- trunk/src/endpoints/manager.cpp	(original)
+++ trunk/src/endpoints/manager.cpp	Mon Jun  2 19:40:49 2008
@@ -133,14 +133,10 @@
   SetVideoInputDevice (video);
 
   // Create endpoints
-  h323EP = new GMH323Endpoint (*this, core);
-  AddRouteEntry("pc:.* = h323:<da>");
-	
   pcssEP = new GMPCSSEndpoint (*this, core);
   pcssEP->SetSoundChannelPlayDevice("EKIGA");
   pcssEP->SetSoundChannelRecordDevice("EKIGA");
-  AddRouteEntry("h323:.* = pc:<db>");
-  protocols.push_back (h323EP->get_protocol_name ());
+  protocols.push_back ("h323");
   protocols.push_back ("sip"); //FIXME
 
   // Media formats

Modified: trunk/src/endpoints/opal-main.cpp
==============================================================================
--- trunk/src/endpoints/opal-main.cpp	(original)
+++ trunk/src/endpoints/opal-main.cpp	Mon Jun  2 19:40:49 2008
@@ -45,6 +45,7 @@
 #include "manager.h"
 #include "ekiga.h"
 #include "sip.h"
+#include "h323.h"
 
 
 static bool
@@ -66,6 +67,7 @@
 
   bool result = true;
   unsigned sip_port = gm_conf_get_int (SIP_KEY "listen_port");
+  unsigned h323_port = gm_conf_get_int (H323_KEY "listen_port");
 
   contact_core = dynamic_cast<Ekiga::ContactCore *> (core.get ("contact-core"));
   presence_core = dynamic_cast<Ekiga::PresenceCore *> (core.get ("presence-core"));
@@ -74,8 +76,10 @@
 
   GMManager *manager = new GMManager (core);
   GMSIPEndpoint *sipEP = new GMSIPEndpoint (*manager, core, sip_port);
+  GMH323Endpoint *h323EP = new GMH323Endpoint (*manager, core, h323_port);
 
   manager->add_protocol_manager (*sipEP);
+  manager->add_protocol_manager (*h323EP);
 
   call_core->add_manager (*manager);
   core.add (*manager); // FIXME temporary

Modified: trunk/src/endpoints/sip.cpp
==============================================================================
--- trunk/src/endpoints/sip.cpp	(original)
+++ trunk/src/endpoints/sip.cpp	Mon Jun  2 19:40:49 2008
@@ -174,7 +174,6 @@
 }
 
 
-
 void
 GMSIPEndpoint::fetch (const std::string _uri)
 {
@@ -300,30 +299,6 @@
   return protocol_name;
 }
 
-void GMSIPEndpoint::set_forward_uri (const std::string & uri)
-{
-  forward_uri = uri;
-}
-
-
-const std::string & GMSIPEndpoint::get_forward_uri () const
-{
-  return forward_uri;
-}
-
-
-void GMSIPEndpoint::set_outbound_proxy (const std::string & uri)
-{
-  outbound_proxy = uri;
-  SetProxy (SIPURL (outbound_proxy));
-}
-
-
-const std::string & GMSIPEndpoint::get_outbound_proxy () const
-{
-  return outbound_proxy;
-}
-
 
 void GMSIPEndpoint::set_dtmf_mode (unsigned mode)
 {
@@ -402,6 +377,33 @@
 }
 
 
+
+void GMSIPEndpoint::set_forward_uri (const std::string & uri)
+{
+  forward_uri = uri;
+}
+
+
+const std::string & GMSIPEndpoint::get_forward_uri () const
+{
+  return forward_uri;
+}
+
+
+void GMSIPEndpoint::set_outbound_proxy (const std::string & uri)
+{
+  outbound_proxy = uri;
+  SetProxy (SIPURL (outbound_proxy));
+}
+
+
+const std::string & GMSIPEndpoint::get_outbound_proxy () const
+{
+  return outbound_proxy;
+}
+
+
+
 void GMSIPEndpoint::GMSIPEndpoint::set_nat_binding_delay (unsigned delay)
 {
   SetNATBindingTimeout (PTimeInterval (0, delay));

Modified: trunk/src/endpoints/sip.h
==============================================================================
--- trunk/src/endpoints/sip.h	(original)
+++ trunk/src/endpoints/sip.h	Mon Jun  2 19:40:49 2008
@@ -70,7 +70,8 @@
 
   GMSIPEndpoint (GMManager &ep, Ekiga::ServiceCore & core, unsigned listen_port);
 
-  /***/
+
+  /* ContactDecorator and PresentityDecorator */
   bool populate_menu (Ekiga::Contact &contact,
                       Ekiga::MenuBuilder &builder);
 
@@ -81,9 +82,13 @@
                                  std::map<std::string, std::string> & uris,
                                  Ekiga::MenuBuilder & builder);
 
-  /***/
+
+  /* PresenceFetcher */
   void fetch (const std::string uri);
   void unfetch (const std::string uri);
+
+
+  /* PresencePublisher */
   void publish (const Ekiga::PersonalDetails & details);
 
 
@@ -92,10 +97,9 @@
                      const std::string & message);
 
 
-  /* ProtocolManager */
+  /* CallProtocolManager */
   bool dial (const std::string & uri); 
 
-
   const std::string & get_protocol_name () const;
 
   void set_dtmf_mode (unsigned mode);
@@ -104,7 +108,8 @@
   bool set_listen_port (unsigned port);
   const Ekiga::CallProtocolManager::Interface & get_listen_interface () const;
 
-  /* SIP ProtocolManager */
+
+  /* SIP CallProtocolManager */
   void set_nat_binding_delay (unsigned delay);
   unsigned get_nat_binding_delay ();
 
@@ -115,7 +120,7 @@
   const std::string & get_forward_uri () const;
 
 
-  /* OPAL STUFF */
+  /* OPAL Methods */
   void Register (const PString & aor,
                  const PString & authUserName,
                  const PString & password,
@@ -145,6 +150,8 @@
 
   SIPURL GetRegisteredPartyName (const SIPURL & host);
 
+
+  /* Callbacks */
 private:
   void on_dial (std::string uri);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]