(file) Return to ModuleController.h CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / Common

Diff for /pegasus/src/Pegasus/Common/ModuleController.h between version 1.37 and 1.45

version 1.37, 2004/05/18 11:03:38 version 1.45, 2006/07/11 18:39:28
Line 1 
Line 1 
 //%2003////////////////////////////////////////////////////////////////////////  //%2006////////////////////////////////////////////////////////////////////////
 // //
 // Copyright (c) 2000, 2001, 2002  BMC Software, Hewlett-Packard Development  // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
 // Company, L. P., IBM Corp., The Open Group, Tivoli Systems.  // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L. P.; // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L. P.;
 // IBM Corp.; EMC Corporation, The Open Group. // IBM Corp.; EMC Corporation, The Open Group.
   // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
   // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
   // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
   // EMC Corporation; VERITAS Software Corporation; The Open Group.
   // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
   // EMC Corporation; Symantec Corporation; The Open Group.
 // //
 // Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to // of this software and associated documentation files (the "Software"), to
Line 26 
Line 32 
 // Author: Mike Day (mdday@us.ibm.com) <<< Wed Mar 13 20:49:40 2002 mdd >>> // Author: Mike Day (mdday@us.ibm.com) <<< Wed Mar 13 20:49:40 2002 mdd >>>
 // //
 // Modified By: Amit K Arora, IBM (amita@in.ibm.com) // Modified By: Amit K Arora, IBM (amita@in.ibm.com)
   //              David Dillard, VERITAS Software Corp.
   //                  (david.dillard@veritas.com)
 // //
 //%///////////////////////////////////////////////////////////////////////////// //%/////////////////////////////////////////////////////////////////////////////
  
Line 45 
Line 53 
 #include <Pegasus/Common/peg_authorization.h> #include <Pegasus/Common/peg_authorization.h>
 #include <Pegasus/Common/Linkage.h> #include <Pegasus/Common/Linkage.h>
 #include <Pegasus/Common/AutoPtr.h> #include <Pegasus/Common/AutoPtr.h>
   #include <Pegasus/Common/List.h>
  
  
 PEGASUS_NAMESPACE_BEGIN PEGASUS_NAMESPACE_BEGIN
Line 52 
Line 61 
 class ModuleController; class ModuleController;
  
  
 class PEGASUS_COMMON_LINKAGE pegasus_module  class PEGASUS_COMMON_LINKAGE pegasus_module : public Linkable
 { {
    private:    private:
       class module_rep : public pegasus_auth_handle       class module_rep : public pegasus_auth_handle
Line 67 
Line 76 
                        void (*async_callback)(Uint32, Message *, void *),                        void (*async_callback)(Uint32, Message *, void *),
                        void (*shutdown_notify)(Uint32 code, void *));                        void (*shutdown_notify)(Uint32 code, void *));
  
             ~module_rep(void) ;          ~module_rep();
  
             Boolean operator == (const module_rep *rep) const             Boolean operator == (const module_rep *rep) const
             { if (rep == this ) return true; return false; }          {
               return(rep == this);
           }
  
             Boolean operator == (const module_rep &rep) const             Boolean operator == (const module_rep &rep) const
             { if (rep == *this) return true; return false; }          {
               return(rep == *this);
           }
  
             Boolean operator == (void *rep) const             Boolean operator == (void *rep) const
             { if ( (void *)this == rep ) return true; return false; }          {
               return(reinterpret_cast<const void *>(this) == rep);
           }
  
             void reference(void) { _reference_count++; }          void reference()
             void dereference(void) { _reference_count--; }          {
             Uint32 reference_count(void)  { return _reference_count.value(); }              _reference_count++;
             const String & get_name(void) const { return _name; }          }
             void *get_module_address(void) const { return _module_address; }  
           void dereference()
           {
               _reference_count--;
           }
   
           Uint32 reference_count() const
           {
               return _reference_count.get();
           }
   
           const String& get_name() const throw()
           {
               return _name;
           }
   
           void *get_module_address() const
           {
               return _module_address;
           }
  
             Message * module_receive_message(Message *msg);             Message * module_receive_message(Message *msg);
  
             void _send_async_callback(Uint32 msg_handle, Message *msg, void *parm);             void _send_async_callback(Uint32 msg_handle, Message *msg, void *parm);
  
             void _send_shutdown_notify(void);          void _send_shutdown_notify();
             void lock(void) { _thread_safety.lock(pegasus_thread_self()); }  
             void unlock(void) { _thread_safety.unlock(); }          void lock()
           {
               _thread_safety.lock(pegasus_thread_self());
           }
   
           void unlock()
           {
               _thread_safety.unlock();
           }
  
             Boolean authorized(void) ;          Boolean authorized();
             Boolean authorized(Uint32);             Boolean authorized(Uint32);
             Boolean authorized(Uint32, Uint32);             Boolean authorized(Uint32, Uint32);
  
          private:          private:
             module_rep(void);          module_rep();
             module_rep(const module_rep & );             module_rep(const module_rep & );
             module_rep & operator= (const module_rep & rep);             module_rep & operator= (const module_rep & rep);
  
   
             Mutex _thread_safety;             Mutex _thread_safety;
             AutoPtr<ModuleController> _controller;//PEP101          // Don't make this an AutoPtr. Refer to bug 3502
           ModuleController* _controller;
             String _name;             String _name;
             AtomicInt _reference_count;             AtomicInt _reference_count;
             AtomicInt _shutting_down;             AtomicInt _shutting_down;
Line 114 
Line 156 
             void (*_shutdown_notify)(Uint32 code, void *);             void (*_shutdown_notify)(Uint32 code, void *);
  
             static Message * default_receive_message(Message *msg, void *inst)             static Message * default_receive_message(Message *msg, void *inst)
             { throw NotImplemented("Module Receive"); return 0; }          {
               throw NotImplemented("Module Receive");
               return 0;
           }
  
             static void default_async_callback(Uint32 handle, Message *msg, void *inst)             static void default_async_callback(Uint32 handle, Message *msg, void *inst)
             { throw NotImplemented("Module Async Receive"); }          {
               throw NotImplemented("Module Async Receive");
           }
  
             static void default_shutdown_notify(Uint32 code, void *inst)             static void default_shutdown_notify(Uint32 code, void *inst)
             { return; }          {
               // Intentionally left blank
           }
  
             static Message * closed_receive_message(Message *msg, void *inst)             static Message * closed_receive_message(Message *msg, void *inst)
             { throw ModuleClosed(); return 0; }          {
               throw ModuleClosed();
               return 0;
           }
  
             static void closed_async_callback(Uint32 handle, Message *msg, void *inst)             static void closed_async_callback(Uint32 handle, Message *msg, void *inst)
             { throw ModuleClosed(); }          {
               throw ModuleClosed();
           }
  
             friend class ModuleController;             friend class ModuleController;
       };       };
Line 142 
Line 196 
       pegasus_module(const pegasus_module & mod);       pegasus_module(const pegasus_module & mod);
       pegasus_module & operator= (const pegasus_module & mod);       pegasus_module & operator= (const pegasus_module & mod);
  
       virtual ~pegasus_module(void);      virtual ~pegasus_module();
  
       virtual Boolean authorized(Uint32 operation);       virtual Boolean authorized(Uint32 operation);
       virtual Boolean authorized(void);      virtual Boolean authorized();
  
       Boolean operator == (const pegasus_module & mod) const ;       Boolean operator == (const pegasus_module & mod) const ;
       Boolean operator == (const String &  mod) const;       Boolean operator == (const String &  mod) const;
       Boolean operator == (const void *mod) const;       Boolean operator == (const void *mod) const;
  
       const String & get_name(void) const;      const String & get_name() const;
  
       // introspection interface       // introspection interface
       Boolean query_interface(const String & class_id, void **object_ptr) const;       Boolean query_interface(const String & class_id, void **object_ptr) const;
  
   
    private:    private:
  
       AutoPtr<module_rep> _rep;//PEP101       AutoPtr<module_rep> _rep;//PEP101
  
       pegasus_module(void)      pegasus_module()
       {       {
       }       }
  
       Boolean _rcv_msg(Message *) ;       Boolean _rcv_msg(Message *) ;
       Message * _receive_message(Message *msg);       Message * _receive_message(Message *msg);
       void _send_async_callback(Uint32 msg_handle, Message *msg, void *) ;       void _send_async_callback(Uint32 msg_handle, Message *msg, void *) ;
       void _send_shutdown_notify(void);      void _send_shutdown_notify();
       Boolean _shutdown(void);      Boolean _shutdown();
       PEGASUS_STD(bitset<32>) _allowed_operations;       PEGASUS_STD(bitset<32>) _allowed_operations;
  
       void reference(void) { _rep->reference(); }      void reference()
       void dereference(void)  { _rep->dereference(); }      {
           _rep->reference();
       }
   
       void dereference()
       {
           _rep->dereference();
       }
   
       friend class ModuleController;       friend class ModuleController;
 }; };
  
  
 class PEGASUS_COMMON_LINKAGE ModuleController : public MessageQueueService class PEGASUS_COMMON_LINKAGE ModuleController : public MessageQueueService
 { {
   
   
    public:    public:
       typedef MessageQueueService Base;       typedef MessageQueueService Base;
  
Line 233 
Line 292 
             {             {
             }             }
  
             ~client_handle(void)          ~client_handle()
             {             {
             }             }
  
Line 248 
Line 307 
  
             virtual Boolean authorized(Uint32, Uint32);             virtual Boolean authorized(Uint32, Uint32);
             virtual Boolean authorized(Uint32 operation);             virtual Boolean authorized(Uint32 operation);
             virtual Boolean authorized(void);          virtual Boolean authorized();
             PEGASUS_STD(bitset<32>) allowed_operations;             PEGASUS_STD(bitset<32>) allowed_operations;
             AtomicInt reference_count;             AtomicInt reference_count;
   
       };       };
  
       class callback_handle       class callback_handle
       {       {
          public:          public:
             static void * operator new(size_t );  
             static void operator delete(void *, size_t);  
          private:  
             static callback_handle *_head;  
             static const int BLOCK_SIZE;  
             static Mutex _alloc_mut;  
   
          public:  
             callback_handle(pegasus_module * module, void *parm)             callback_handle(pegasus_module * module, void *parm)
                : _module(module), _parm(parm)                : _module(module), _parm(parm)
             {             {
Line 281 
Line 331 
             void *_parm;             void *_parm;
       };       };
  
   
    public:    public:
   
   
       ModuleController(const char *name);       ModuleController(const char *name);
 /*       ModuleController(const char *name,  */ /*       ModuleController(const char *name,  */
 /*                     Sint16 min_threads,  */ /*                     Sint16 min_threads,  */
 /*                     Sint16 max_threads, */ /*                     Sint16 max_threads, */
 /*                     struct timeval & create_thread, */ /*                     struct timeval & create_thread, */
 /*                     struct timeval & destroy_thread, */  /*             struct timeval & destroy_thread); */
 /*                     struct timeval & deadlock); */  
   
   
       ~ModuleController(void);  
   
   
  
       ~ModuleController();
  
       // module api       // module api
       // @exception AlreadyExistsException
       // @exception IncompatibleTypesException
       static ModuleController & register_module(const String & controller_name,       static ModuleController & register_module(const String & controller_name,
                                                 const String & module_name,                                                 const String & module_name,
                                                 void *module_address,                                                 void *module_address,
                                                 Message * (*receive_message)(Message *, void *),                                                 Message * (*receive_message)(Message *, void *),
                                                 void (*async_callback)(Uint32, Message *, void *),                                                 void (*async_callback)(Uint32, Message *, void *),
                                                 void (*shutdown_notify)(Uint32, void *),                                                 void (*shutdown_notify)(Uint32, void *),
                                                 pegasus_module **instance = NULL)                      pegasus_module **instance = NULL);
   
          throw(AlreadyExistsException, IncompatibleTypesException);  
  
       Boolean deregister_module(const String & module_name)      // @exception Permission
          throw(Permission);      Boolean deregister_module(const String & module_name);
  
       Uint32 find_service(const pegasus_module & handle, const String & name) throw(Permission);      // @exception Permission
       Uint32 find_service(const pegasus_module & handle, const String & name);
  
       // @exception Permission
       // @exception IPCException
       Uint32 find_module_in_service(const pegasus_module & handle,       Uint32 find_module_in_service(const pegasus_module & handle,
                                     const String & module_name)                      const String & module_name);
          throw(Permission, IPCException);  
   
  
       // @exception Permission
       pegasus_module * get_module_reference(const pegasus_module & my_handle,       pegasus_module * get_module_reference(const pegasus_module & my_handle,
                                             const String & module_name)                      const String & module_name);
          throw(Permission);  
  
       // send a message to another service       // send a message to another service
       // @exception Permission
       // @exception IPCException
       AsyncReply *ModuleSendWait(const pegasus_module & handle,       AsyncReply *ModuleSendWait(const pegasus_module & handle,
                                  Uint32 destination_q,                                  Uint32 destination_q,
                                  AsyncRequest *request) throw(Permission, IPCException);                      AsyncRequest *request);
  
       // send a message to another module via another service       // send a message to another module via another service
       // @exception Permission
       // @exception DeadLock
       // @exception IPCException
       AsyncReply *ModuleSendWait(const pegasus_module & handle,       AsyncReply *ModuleSendWait(const pegasus_module & handle,
                                  Uint32 destination_q,                                  Uint32 destination_q,
                                  const String & destination_module,                                  const String & destination_module,
                                  AsyncRequest *message) throw(Permission, Deadlock, IPCException);                      AsyncRequest *message);
  
       // send an async message to another service       // send an async message to another service
       // @exception Permission
       // @exception DeadLock
       // @exception IPCException
       Boolean ModuleSendAsync(const pegasus_module & handle,       Boolean ModuleSendAsync(const pegasus_module & handle,
                               Uint32 msg_handle,                               Uint32 msg_handle,
                               Uint32 destination_q,                               Uint32 destination_q,
                               AsyncRequest *message,                               AsyncRequest *message,
                               void *callback_parm) throw(Permission, IPCException);                      void *callback_parm);
  
       // send an async message to another module via another service       // send an async message to another module via another service
       // @exception Permission
       // @exception IPCException
       Boolean ModuleSendAsync(const pegasus_module & handle,       Boolean ModuleSendAsync(const pegasus_module & handle,
                               Uint32 msg_handle,                               Uint32 msg_handle,
                               Uint32 destination_q,                               Uint32 destination_q,
                               const String & destination_module,                               const String & destination_module,
                               AsyncRequest *message,                               AsyncRequest *message,
                               void *callback_parm) throw(Permission, IPCException);                      void *callback_parm);
  
       // @exception Permission
       // @exception IPCException
       Boolean ModuleSendForget(const pegasus_module & handle,       Boolean ModuleSendForget(const pegasus_module & handle,
                                Uint32 destination_q,                                Uint32 destination_q,
                                AsyncRequest *message)                      AsyncRequest *message);
          throw(Permission, IPCException);  
  
       // @exception Permission
       // @exception IPCException
       Boolean ModuleSendForget(const pegasus_module & handle,       Boolean ModuleSendForget(const pegasus_module & handle,
                                Uint32 destination_q,                                Uint32 destination_q,
                                const String & destination_module,                                const String & destination_module,
                                AsyncRequest *message)                      AsyncRequest *message);
          throw(Permission, IPCException);  
  
       // @exception Permission
       // @exception Deadlock
       // @exception IPCException
       void blocking_thread_exec(const pegasus_module & handle,       void blocking_thread_exec(const pegasus_module & handle,
                                 PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *thread_func)(void *),                                 PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *thread_func)(void *),
                                 void *parm) throw(Permission, Deadlock, IPCException);                      void *parm);
   
       // @exception Permission
       // @exception Deadlock
       // @exception IPCException
       void async_thread_exec(const pegasus_module & handle,       void async_thread_exec(const pegasus_module & handle,
                              PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *thread_func)(void *),                              PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *thread_func)(void *),
                              void *parm) throw(Permission, Deadlock, IPCException);                      void *parm);
  
       Boolean verify_handle(pegasus_module *);       Boolean verify_handle(pegasus_module *);
  
       // @exception IncompatibleTypesException
       static ModuleController & get_client_handle(const pegasus_identity & id,       static ModuleController & get_client_handle(const pegasus_identity & id,
                                                   client_handle **handle)                      client_handle **handle);
          throw(IncompatibleTypesException);  
  
       // @exception IncompatibleTypesException
       static ModuleController & get_client_handle(const char *controller,       static ModuleController & get_client_handle(const char *controller,
                                                   const pegasus_identity & id,                                                   const pegasus_identity & id,
                                                   client_handle **handle)                      client_handle **handle);
          throw(IncompatibleTypesException);  
  
  
       void return_client_handle(client_handle *handle);       void return_client_handle(client_handle *handle);
  
       // send a message to another service       // send a message to another service
       // @exception Permission
       // @exception IPCException
       AsyncReply *ClientSendWait(const client_handle & handle,       AsyncReply *ClientSendWait(const client_handle & handle,
                                  Uint32 destination_q,                      Uint32 destination_q, AsyncRequest *request);
                                  AsyncRequest *request)  
          throw(Permission, IPCException);  
  
       // send a message to another module via another service       // send a message to another module via another service
       // @exception Permission
       // @exception Deadlock
       // @exception IPCException
       AsyncReply *ClientSendWait(const client_handle & handle,       AsyncReply *ClientSendWait(const client_handle & handle,
                                  Uint32 destination_q,                                  Uint32 destination_q,
                                  String & destination_module,                                  String & destination_module,
                                  AsyncRequest *message)                   AsyncRequest *message);
          throw(Permission, Deadlock, IPCException);  
  
       // send an async message to another service       // send an async message to another service
       // @exception Permission
       // @exception IPCException
       Boolean ClientSendAsync(const client_handle & handle,       Boolean ClientSendAsync(const client_handle & handle,
                               Uint32 msg_handle,                               Uint32 msg_handle,
                               Uint32 destination_q,                               Uint32 destination_q,
                               AsyncRequest *message,                               AsyncRequest *message,
                               void (*async_callback)(Uint32, Message *, void *) ,                               void (*async_callback)(Uint32, Message *, void *) ,
                               void *callback_parm)                  void *callback_parm);
          throw(Permission, IPCException);  
  
       // send an async message to another module via another service       // send an async message to another module via another service
       // @exception Permission
       // @exception IPCException
       Boolean ClientSendAsync(const client_handle & handle,       Boolean ClientSendAsync(const client_handle & handle,
                               Uint32 msg_handle,                               Uint32 msg_handle,
                               Uint32 destination_q,                               Uint32 destination_q,
                               const String & destination_module,                               const String & destination_module,
                               AsyncRequest *message,                               AsyncRequest *message,
                               void (*async_callback)(Uint32, Message *, void *),                               void (*async_callback)(Uint32, Message *, void *),
                               void *callback_parm )                  void *callback_parm);
          throw(Permission, IPCException);  
  
       // @exception Permission
       // @exception IPCException
       Boolean ClientSendForget(const client_handle & handle,       Boolean ClientSendForget(const client_handle & handle,
                                Uint32 destination_q,                                Uint32 destination_q,
                                AsyncRequest *message)                  AsyncRequest *message);
          throw(Permission, IPCException);  
  
       // @exception Permission
       // @exception IPCException
       Boolean ClientSendForget(const client_handle & handle,       Boolean ClientSendForget(const client_handle & handle,
                                Uint32 destination_q,                                Uint32 destination_q,
                                const String & destination_module,                                const String & destination_module,
                                AsyncRequest *message)                  AsyncRequest *message);
          throw(Permission, IPCException);  
  
       // @exception Permission
       // @exception Deadlock
       // @exception IPCException
       void client_blocking_thread_exec(const client_handle & handle,       void client_blocking_thread_exec(const client_handle & handle,
                                        PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *thread_func)(void *),                                        PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *thread_func)(void *),
                                        void *parm)                  void *parm);
          throw(Permission, Deadlock, IPCException);  
       // @exception Permission
       // @exception Deadlock
       // @exception IPCException
       void client_async_thread_exec(const client_handle & handle,       void client_async_thread_exec(const client_handle & handle,
                                     PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *thread_func)(void *),                                     PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *thread_func)(void *),
                                     void *parm)                  void *parm);
          throw(Permission, Deadlock, IPCException);  
  
    protected:    protected:
       // ATTN-RK-P2-20010322:  These methods are pure virtual in superclass       // ATTN-RK-P2-20010322:  These methods are pure virtual in superclass
       virtual void handleEnqueue(void) {}      virtual void handleEnqueue() {}
       virtual void handleEnqueue(Message *) {}       virtual void handleEnqueue(Message *) {}
       virtual void _handle_async_request(AsyncRequest *rq);       virtual void _handle_async_request(AsyncRequest *rq);
       virtual void _handle_async_callback(AsyncOpNode *op);       virtual void _handle_async_callback(AsyncOpNode *op);
  
    private:    private:
   
   
       class _module_lock       class _module_lock
       {       {
          public:          public:
             _module_lock(DQueue<pegasus_module> * list)          _module_lock(List<pegasus_module, RecursiveMutex> * list)
                :_list(list)                :_list(list)
             {             {
                _list->lock();                _list->lock();
   
             }             }
             ~_module_lock(void)  
           ~_module_lock()
             {             {
                _list->unlock();                _list->unlock();
             }             }
  
   
          private:          private:
             _module_lock();             _module_lock();
             DQueue<pegasus_module> * _list;          List<pegasus_module, RecursiveMutex> * _list;
       };       };
  
  
  
       static void _async_handleEnqueue(AsyncOpNode *h, MessageQueue *q, void *parm);       static void _async_handleEnqueue(AsyncOpNode *h, MessageQueue *q, void *parm);
       DQueue<pegasus_module> _modules;      List<pegasus_module, RecursiveMutex> _modules;
       pegasus_module _internal_module;  
       AsyncReply *_send_wait(Uint32, AsyncRequest *);       AsyncReply *_send_wait(Uint32, AsyncRequest *);
       AsyncReply *_send_wait(Uint32, const String &, AsyncRequest *);       AsyncReply *_send_wait(Uint32, const String &, AsyncRequest *);
       Boolean _send_forget(Uint32, AsyncRequest *) throw(IPCException);  
       Boolean _send_forget(Uint32, const String &, AsyncRequest *) throw(IPCException);      // @exception IPCException
       Boolean _send_forget(Uint32, AsyncRequest *);
   
       // @exception IPCException
       Boolean _send_forget(Uint32, const String &, AsyncRequest *);
  
       void _blocking_thread_exec(       void _blocking_thread_exec(
          PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *thread_func)(void *),          PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *thread_func)(void *),
          void *parm) ;          void *parm) ;
   
       void _async_thread_exec(       void _async_thread_exec(
          PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *thread_func)(void *),          PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *thread_func)(void *),
          void *parm) ;          void *parm) ;
 }; };
  
   
   
   
   
   
   
   
   
 PEGASUS_NAMESPACE_END PEGASUS_NAMESPACE_END
  
   
 #endif // Pegasus_Module_Controller_H #endif // Pegasus_Module_Controller_H


Legend:
Removed from v.1.37  
changed lines
  Added in v.1.45

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2