summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorschmidt <douglascraigschmidt@users.noreply.github.com>1998-09-07 04:49:01 +0000
committerschmidt <douglascraigschmidt@users.noreply.github.com>1998-09-07 04:49:01 +0000
commitdceee5506c4b747d6c3801d3f1649f9305dff2d5 (patch)
treec487fc2eb5a13824b27c6983a5620f90c4442fe8 /apps
parent027290ebc37d5dd85440815f3d5840cd83b51b7a (diff)
downloadATCD-dceee5506c4b747d6c3801d3f1649f9305dff2d5.tar.gz
*** empty log message ***
Diffstat (limited to 'apps')
-rw-r--r--apps/drwho/BS_Client.cpp75
-rw-r--r--apps/drwho/BS_Client.h49
-rw-r--r--apps/drwho/BS_Server.cpp113
-rw-r--r--apps/drwho/BS_Server.h47
-rw-r--r--apps/drwho/Binary_Search.cpp77
-rw-r--r--apps/drwho/Binary_Search.h71
-rw-r--r--apps/drwho/CM_Client.cpp129
-rw-r--r--apps/drwho/CM_Client.h53
-rw-r--r--apps/drwho/CM_Server.cpp85
-rw-r--r--apps/drwho/CM_Server.h41
-rw-r--r--apps/drwho/ChangeLog239
-rw-r--r--apps/drwho/Comm_Manager.h26
-rw-r--r--apps/drwho/Drwho_Node.cpp87
-rw-r--r--apps/drwho/Drwho_Node.h121
-rw-r--r--apps/drwho/EXAMPLE311
-rw-r--r--apps/drwho/File_Manager.cpp162
-rw-r--r--apps/drwho/File_Manager.h31
-rw-r--r--apps/drwho/HT_Client.cpp27
-rw-r--r--apps/drwho/HT_Client.h16
-rw-r--r--apps/drwho/HT_Server.cpp29
-rw-r--r--apps/drwho/HT_Server.h16
-rw-r--r--apps/drwho/Hash_Table.cpp90
-rw-r--r--apps/drwho/Hash_Table.h30
-rw-r--r--apps/drwho/Makefile427
-rw-r--r--apps/drwho/Multicast_Manager.cpp170
-rw-r--r--apps/drwho/Multicast_Manager.h55
-rw-r--r--apps/drwho/Options.cpp152
-rw-r--r--apps/drwho/Options.h71
-rw-r--r--apps/drwho/PMC_All.cpp85
-rw-r--r--apps/drwho/PMC_All.h28
-rw-r--r--apps/drwho/PMC_Flo.cpp99
-rw-r--r--apps/drwho/PMC_Flo.h28
-rw-r--r--apps/drwho/PMC_Ruser.cpp137
-rw-r--r--apps/drwho/PMC_Ruser.h29
-rw-r--r--apps/drwho/PMC_Usr.cpp93
-rw-r--r--apps/drwho/PMC_Usr.h30
-rw-r--r--apps/drwho/PMS_All.cpp76
-rw-r--r--apps/drwho/PMS_All.h27
-rw-r--r--apps/drwho/PMS_Flo.cpp58
-rw-r--r--apps/drwho/PMS_Flo.h26
-rw-r--r--apps/drwho/PMS_Ruser.cpp103
-rw-r--r--apps/drwho/PMS_Ruser.h28
-rw-r--r--apps/drwho/PMS_Usr.cpp66
-rw-r--r--apps/drwho/PMS_Usr.h26
-rw-r--r--apps/drwho/PM_Client.cpp106
-rw-r--r--apps/drwho/PM_Client.h37
-rw-r--r--apps/drwho/PM_Server.cpp72
-rw-r--r--apps/drwho/PM_Server.h35
-rw-r--r--apps/drwho/Protocol_Manager.cpp83
-rw-r--r--apps/drwho/Protocol_Manager.h86
-rw-r--r--apps/drwho/Protocol_Record.cpp79
-rw-r--r--apps/drwho/Protocol_Record.h95
-rw-r--r--apps/drwho/Rwho_DB_Manager.cpp104
-rw-r--r--apps/drwho/Rwho_DB_Manager.h31
-rw-r--r--apps/drwho/SL_Client.cpp14
-rw-r--r--apps/drwho/SL_Client.h29
-rw-r--r--apps/drwho/SL_Server.cpp21
-rw-r--r--apps/drwho/SL_Server.h37
-rw-r--r--apps/drwho/SML_Client.cpp35
-rw-r--r--apps/drwho/SML_Client.h32
-rw-r--r--apps/drwho/SML_Server.cpp10
-rw-r--r--apps/drwho/SML_Server.h25
-rw-r--r--apps/drwho/SMR_Client.cpp19
-rw-r--r--apps/drwho/SMR_Client.h28
-rw-r--r--apps/drwho/SMR_Server.cpp14
-rw-r--r--apps/drwho/SMR_Server.h28
-rw-r--r--apps/drwho/SM_Client.cpp61
-rw-r--r--apps/drwho/SM_Client.h39
-rw-r--r--apps/drwho/SM_Server.cpp59
-rw-r--r--apps/drwho/SM_Server.h32
-rw-r--r--apps/drwho/Search_Struct.cpp20
-rw-r--r--apps/drwho/Search_Struct.h42
-rw-r--r--apps/drwho/Select_Manager.h12
-rw-r--r--apps/drwho/Single_Lookup.cpp29
-rw-r--r--apps/drwho/Single_Lookup.h51
-rw-r--r--apps/drwho/client.cpp61
-rw-r--r--apps/drwho/global.h35
-rw-r--r--apps/drwho/new.cpp215
-rw-r--r--apps/drwho/new.h27
-rw-r--r--apps/drwho/rwhod.h38
-rw-r--r--apps/drwho/server.cpp96
81 files changed, 5576 insertions, 0 deletions
diff --git a/apps/drwho/BS_Client.cpp b/apps/drwho/BS_Client.cpp
new file mode 100644
index 00000000000..9630f8713df
--- /dev/null
+++ b/apps/drwho/BS_Client.cpp
@@ -0,0 +1,75 @@
+// $Id$
+#include "Options.h"
+#include "new.h"
+#include "File_Manager.h"
+#include "BS_Client.h"
+
+BS_Client::BS_Client (void)
+{
+ this->count_ = File_Manager::open_file (Options::friend_file);
+
+ if (this->count_ < 0)
+ ACE_ERROR ((LM_ERROR, "%p\n"n, Options::program_name));
+ else
+ {
+ this->protocol_record_ =
+ new (PRIVATE_POOL) Protocol_Record[this->count_];
+ this->sorted_record_ =
+ new (PRIVATE_POOL) Protocol_Record *[this->count_];
+
+ for (int i = 0; i < this->count_; i++)
+ {
+ Protocol_Record *rec_ptr = &this->protocol_record_[i];
+ this->sorted_record_[i] = rec_ptr;
+ File_Manager::get_login_and_real_name (rec_ptr->key_name1_,
+ rec_ptr->key_name2_);
+ }
+
+ ACE_OS::qsort (this->sorted_record_,
+ this->count_,
+ sizeof *this->sorted_record_,
+ (int (*)(const void *, const void *)) Binary_Search::name_compare);
+ }
+}
+
+// This function is used to merge the KEY_NAME from server HOST_NAME
+// into the sorted list of userids kept on the client's side. Since
+// we *know* we are going to find the name we use the traditional
+// binary search.
+
+Protocol_Record *
+BS_Client::insert (char *key_name, int)
+{
+ int lo = 0;
+ int hi = this->count_ - 1;
+ Protocol_Record **sorted_buffer = this->sorted_record_;
+
+ while (lo <= hi)
+ {
+ int mid = (lo + hi) / 2;
+ Protocol_Record *frp = sorted_buffer[mid];
+ int cmp = ACE_OS::strcmp (key_name,
+ frp->get_login ());
+
+ if (cmp == 0)
+ return frp;
+ else if (cmp < 0)
+ hi = mid - 1;
+ else
+ lo = mid + 1;
+ }
+
+ return 0;
+}
+
+Protocol_Record *
+BS_Client::get_each_entry (void)
+{
+ Protocol_Record *frp;
+
+ while ((frp = Binary_Search::get_each_entry ()) != 0)
+ if (frp->get_drwho_list () != 0)
+ return frp;
+
+ return 0;
+}
diff --git a/apps/drwho/BS_Client.h b/apps/drwho/BS_Client.h
new file mode 100644
index 00000000000..bab7cd2f76f
--- /dev/null
+++ b/apps/drwho/BS_Client.h
@@ -0,0 +1,49 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// drwho
+//
+// = FILENAME
+// BS_Client.h
+//
+// = DESCRIPTION
+// Provides the client's binary search lookup table abstraction.
+//
+// = AUTHOR
+// Douglas C. Schmidt
+//
+// ============================================================================
+
+#if !defined (_BS_CLIENT_H)
+#define _BS_CLIENT_H
+
+#include "Binary_Search.h"
+
+class BS_Client : public Binary_Search
+{
+ // = TITLE
+ // Provides the client's binary search lookup table abstraction.
+public:
+ // = Initialization.
+ BS_Client (void);
+ // Constructor.
+
+ virtual Protocol_Record *insert (char *key_name,
+ int max_len = MAXUSERIDNAMELEN);
+ // This function is used to merge the <key_name> from server
+ // <host_name> into the sorted list of userids kept on the client's
+ // side. Since we *know* we are going to find the name we use the
+ // traditional binary search.
+
+ virtual Protocol_Record *get_each_entry (void);
+ // An iterator, similar to Binary_Search::get_next_friend, though in
+ // this case the friend records are returned in the order they
+ // appeared in the friend file, rather than in sorted order. Also,
+ // we skip over entries that don't have any hosts associated with
+ // them.
+};
+
+#endif /* _BS_CLIENT_H */
diff --git a/apps/drwho/BS_Server.cpp b/apps/drwho/BS_Server.cpp
new file mode 100644
index 00000000000..16e344b7cb2
--- /dev/null
+++ b/apps/drwho/BS_Server.cpp
@@ -0,0 +1,113 @@
+// $Id$
+#include "BS_Server.h"
+#include "new.h"
+
+// This constructor takes a message of sorted login names and loads up
+// the symbol table on the server's side. It assumes that the number
+// of friends is stored in the first MAXUSERIDNAMELEN bytes of the
+// packet. Note that we assume that the client sends the login names
+// in sorted order, so we don't bother sorting them!
+
+BS_Server::BS_Server (char *packet)
+{
+ char *buf_ptr = packet + MAXUSERIDNAMELEN;
+
+ this->count_ = atoi (packet);
+ this->buffer_ = buf_ptr;
+ this->protocol_record_ =
+ new (PRIVATE_POOL) Protocol_Record[this->count_];
+ this->sorted_record_ =
+ new (PRIVATE_POOL) Protocol_Record *[this->count_];
+
+ for (int i = 0; i < this->count_; i++)
+ {
+ Protocol_Record *rec_ptr = &this->protocol_record_[i];
+
+ this->sorted_record_[i] = rec_ptr;
+ rec_ptr->key_name1_ = buf_ptr;
+
+ // Skip forward to the start of the next login name.
+
+ while (*buf_ptr++ != '\0')
+ continue;
+ }
+
+}
+
+// Insert the HOST_NAME into the appropriate DRWHO_LIST slot if the
+// KEY_NAME happens to be one of our friends. Binary search is used
+// because the Protocol_Manager keeps a sorted representation of the
+// friend names.
+//
+// Note that this binary search is tuned for unsuccessful searches,
+// since most of the time we the KEY_NAME is *not* a friend (unless
+// you've got *lots* of friends)!
+//
+// Note finally that we keep a cache of the last KEY_NAME that is
+// looked up, as well as the result of the lookup. This speeds things
+// up because the whod files tend to cluster userids together. */
+
+Protocol_Record *
+BS_Server::insert (char *key_name, int max_len)
+{
+ static char last_lookup[MAXHOSTNAMELEN];
+ static int mid = 0;
+ static int result = 0;
+ Protocol_Record **buffer = this->sorted_record;
+
+ // First check the cache...
+ if (ACE_OS::strncmp (last_lookup, key_name, max_len) == 0)
+ {
+ if (result == 0)
+ return 0;
+ }
+ else
+ {
+ // Store this away in the cache for the next iteration.
+ ACE_OS::strncpy (last_lookup, key_name, max_len);
+
+ int hi = this->count - 1;
+ int lo = 0;
+ int cmp;
+
+ while (lo < hi)
+ {
+ mid = (hi + lo + 1) / 2;
+
+ cmp = ACE_OS::strncmp (key_name, buffer[mid]->get_login (), max_len);
+
+ if (cmp < 0)
+ hi = mid - 1;
+ else
+ lo = mid;
+ }
+
+ // This line is very subtle... ;-)
+ if (!(cmp == 0 || ACE_OS::strncmp (key_name, buffer[--mid]->get_login (), max_len) == 0))
+ {
+ result = 0;
+ return 0;
+ }
+ }
+
+ // If we get here we've located a friend.
+
+ result = 1;
+ return buffer[mid];
+}
+
+// Returns the next friend in the sequence of sorted friends. Skips
+// over the entries that don't have any hosts associated with them
+// (because these entries weren't on the server machine. */
+
+Protocol_Record *
+BS_Server::get_next_entry (void)
+{
+ Protocol_Record *frp;
+
+ while ((frp = Binary_Search::get_next_entry ()) != 0)
+ if (frp->get_drwho_list () != 0)
+ return frp;
+
+ return 0;
+}
diff --git a/apps/drwho/BS_Server.h b/apps/drwho/BS_Server.h
new file mode 100644
index 00000000000..d821acc7cf5
--- /dev/null
+++ b/apps/drwho/BS_Server.h
@@ -0,0 +1,47 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// drwho
+//
+// = FILENAME
+// BS_Server.h
+//
+// = DESCRIPTION
+// Provides the server's binary search lookup table abstraction.
+//
+// = AUTHOR
+// Douglas C. Schmidt
+//
+// ============================================================================
+
+#if !defined (_BS_SERVER_H)
+#define _BS_SERVER_H
+
+#include "Binary_Search.h"
+
+class BS_Server : public Binary_Search
+ // = TITLE
+ // Provides the server's binary search lookup table abstraction.
+{
+public:
+ // = Initialization.
+ BS_Server (char *packet);
+
+ virtual Protocol_Record *insert (char *key_name,
+ int max_len = MAXUSERIDNAMELEN);
+ // This function is used to merge the <key_name> from server
+ // <host_name> into the sorted list of userids kept on the client's
+ // side.
+
+ virtual Protocol_Record *get_next_entry (void);
+ // An iterator, similar to Binary_Search::get_next_friend, though in
+ // this case the friend records are returned in the order they
+ // appeared in the friend file, rather than in sorted order. Also,
+ // we skip over entries that don't have any hosts associated with
+ // them.
+};
+
+#endif /* _BS_SERVER_H */
diff --git a/apps/drwho/Binary_Search.cpp b/apps/drwho/Binary_Search.cpp
new file mode 100644
index 00000000000..237ea882875
--- /dev/null
+++ b/apps/drwho/Binary_Search.cpp
@@ -0,0 +1,77 @@
+// $Id$
+#include "Options.h"
+#include "Binary_Search.h"
+
+// This function is passed to qsort to perform the comparison between
+// login names for two friends.
+
+int
+Binary_Search::name_compare (void *s1, void *s2)
+{
+ return ACE_OS::strcmp ((*(Protocol_Record **) s1)->key_name1_,
+ (*(Protocol_Record **) s2)->key_name1_);
+}
+
+// Returns the next friend in the sequence of sorted friends. Note
+// that this function would be simplified if we expanded the iterator
+// interface to include an "initialize" and "next" function!
+
+Protocol_Record *
+Binary_Search::get_next_entry (void)
+{
+ // Reset the iterator if we are starting from the beginning.
+
+ if (this->current_ptr_ == 0)
+ this->current_ptr_ = this->sorted_record_;
+
+ // Now check to see if we've hit the end, in which case we set
+ // things up for the next round!
+
+ if (this->current_ptr_ < this->sorted_record_ + this->count_)
+ return *this->current_ptr_++;
+ else
+ {
+ this->current_ptr_ = 0;
+ return 0;
+ }
+}
+
+// An iterator, similar to Binary_Search::get_next_friend, though in
+// this case the friend records are returned in the order they
+// appeared in the friend file, rather than in sorted order. Also, we
+// skip over entries that don't have any hosts associated with them.
+
+Protocol_Record *
+Binary_Search::get_each_entry (void)
+{
+ // Reset the iterator if we are starting from the beginning.
+
+ if (this->current_index_ == -1)
+ this->current_index_ = 0;
+
+ // Now check to see if we've hit the end, in which case we set
+ // things up for the next round!
+
+ for (;
+ this->current_index_ < this->count_;
+ this->current_index_++)
+ if (this->protocol_record_[this->current_index_].drwho_list != 0)
+ return &this->protocol_record_[this->current_index_++];
+
+ this->current_index_ = -1;
+ return 0;
+}
+
+Binary_Search::~Binary_Search (void)
+{
+ if (Options::get_opt (Options::DEBUG))
+ ACE_DEBUG ((LM_DEBUG, "disposing Binary_Search\n"));
+}
+
+// Used to initialize the values for the iterators...
+
+Binary_Search::Binary_Search (void)
+ : current_ptr_ (0),
+ current_index_ (0)
+{
+}
diff --git a/apps/drwho/Binary_Search.h b/apps/drwho/Binary_Search.h
new file mode 100644
index 00000000000..3312fd5c778
--- /dev/null
+++ b/apps/drwho/Binary_Search.h
@@ -0,0 +1,71 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// drwho
+//
+// = FILENAME
+// Binary_Search.h
+//
+// = DESCRIPTION
+// Defines a binary search abstraction for friend records.
+//
+// = AUTHOR
+// Douglas C. Schmidt
+//
+// ============================================================================
+
+#if defined (_BINARY_SEARCH_H)
+#define _BINARY_SEARCH_H
+
+#include "Search_Struct.h"
+
+class Binary_Search : public Search_Struct
+{
+ // = TITLE
+ // Defines a binary search abstraction for friend records.
+public:
+ // = Initialization and termination method.
+ Binary_Search (void);
+ // Initialize the values for the iterators...
+
+ virtual ~Binary_Search (void);
+ // Destructor.
+
+ virtual Protocol_Record *get_next_entry (void);
+ // Returns the next friend in the sequence of sorted friends. Note
+ // that this function would be simplified if we expanded the
+ // iterator interface to include an "initialize" and "next"
+ // function!
+
+ virtual Protocol_Record *get_each_entry (void);
+ // An iterator, similar to Binary_Search::get_next_friend, though in
+ // this case the friend records are returned in the order they
+ // appeared in the friend file, rather than in sorted order. Also,
+ // we skip over entries that don't have any hosts associated with
+ // them.
+
+ virtual Protocol_Record *insert (char *key_name,
+ int max_len = MAXUSERIDNAMELEN) = 0;
+ // This function is used to merge the <key_name> from server
+ // <host_name> into the sorted list of userids kept on the client's
+ // side.
+
+ static int name_compare (void *, void *);
+ // This function is passed to qsort to perform the comparison
+ // between login names for two friends.
+
+protected:
+ Protocol_Record **current_ptr_;
+ int current_index_;
+
+ Protocol_Record *protocol_record_;
+ Protocol_Record **sorted_record_;
+
+ char *buffer_;
+ int buffer_size_;
+};
+
+#endif /* _BINARY_SEARCH_H */
diff --git a/apps/drwho/CM_Client.cpp b/apps/drwho/CM_Client.cpp
new file mode 100644
index 00000000000..88783288ec1
--- /dev/null
+++ b/apps/drwho/CM_Client.cpp
@@ -0,0 +1,129 @@
+// $Id$
+#include "global.h"
+#include "Options.h"
+#include "Multicast_Manager.h"
+#include "CM_Client.h"
+
+// Creates and binds a UDP socket...
+
+int
+CM_Client::open (short port_number)
+{
+ int max_packet_size = UDP_PACKET_SIZE;
+
+ Comm_Manager::sokfd = ACE_OS::socket (PF_INET, SOCK_DGRAM, 0);
+
+ if (Comm_Manager::sokfd == ACE_INVALID_HANDLE)
+ return -1;
+
+ ACE_OS::memset ((char *) &this->sin, 0, sizeof this->sin);
+ this->sin.sin_family = AF_INET;
+ this->sin.sin_port = htons (port_number);
+
+ return 1;
+}
+
+int
+CM_Client::receive (int timeout)
+{
+ FD_ZERO (&this->read_fd_);
+ FD_SET (Comm_Manager::sokfd, &this->read_fd_);
+
+ if (timeout > 0)
+ {
+ this->time_out_.tv_sec = timeout;
+ this->time_out_.tv_usec = 0;
+ this->top_ = &time_out;
+ }
+
+ while (Multicast_Manager::outstanding_hosts_remain ())
+ {
+ if (ACE_OS:;select (Comm_Manager::sokfd + 1,
+ &this->read_fd_, 0, 0,
+ this->top_) <= 0)
+ break;
+ else
+ {
+ int sin_len = sizeof this->sin;
+ ssize_t n = ACE_OS::recvfrom (Comm_Manager::sokfd,
+ this->recv_packet_, UDP_PACKET_SIZE,
+ 0,
+ (sockaddr *) &this->sin,
+ &sin_len);
+
+ if (n < 0)
+ return -1;
+ else
+ {
+ if (Options::get_opt (Options::DEBUG) != 0)
+ {
+ hostent *np = ACE_OS::gethostbyaddr ((char *) &this->sin_.sin_addr,
+ sizeof this->sin_.sin_addr,
+ AF_INET);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "receiving from server host %s (%s)\n",
+ np->h_name,
+ inet_ntoa (this->sin.sin_addr)));
+ }
+
+ if (this->demux (this->recv_packet, n) < 0)
+ return -1;
+
+ Multicast_Manager::checkoff_host (this->sin.sin_addr);
+ }
+ }
+ }
+
+ for (char *host_name;
+ Multicast_Manager::get_next_non_responding_host (host_name);
+ )
+ ACE_DEBUG ((LM_DEBUG,
+ "%s did not respond\n",
+ host_name));
+ return 1;
+}
+
+int
+CM_Client::send (void)
+{
+ int packet_length = 0;
+
+ if (this->mux (this->send_packet, packet_length) < 0)
+ return -1;
+
+ // Ship off the info to all the hosts.
+
+ while (Multicast_Manager::get_next_host_addr (this->sin.sin_addr) != 0)
+ {
+ if (Options::get_opt (Options::DEBUG) != 0)
+ {
+ hostent *np = ACE_OS::gethostbyaddr ((char *) &this->sin.sin_addr,
+ sizeof this->sin.sin_addr,
+ AF_INET);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "sending to server host %s (%s)\n",
+ np->h_name,
+ inet_ntoa (this->sin.sin_addr)));
+ }
+
+ if (sendto (Comm_Manager::sokfd, this->send_packet, packet_length, 0, (sockaddr *) &this->sin, sizeof this->sin) < 0)
+ return -1;
+ }
+ return 1;
+}
+
+CM_Client::CM_Client (void)
+ : top (0)
+{
+}
+
+CM_Client::~CM_Client (void)
+{
+ if (Options::get_opt (Options::DEBUG))
+ ACE_DEBUG ((LM_DEBUG, "disposing CM_Client\n"));
+
+ ACE_OS::closesocket (Comm_Manager::sokfd);
+}
+
diff --git a/apps/drwho/CM_Client.h b/apps/drwho/CM_Client.h
new file mode 100644
index 00000000000..02c386d6e8d
--- /dev/null
+++ b/apps/drwho/CM_Client.h
@@ -0,0 +1,53 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// drwho
+//
+// = FILENAME
+// BS_Server.h
+//
+// = DESCRIPTION
+// Provides a virtual communcations layer for the client in the
+// drwho program.
+//
+// = AUTHOR
+// Douglas C. Schmidt
+//
+// ============================================================================
+
+#if defined (_CM_CLIENT_H)
+#define _CM_CLIENT_H
+
+#include "ace/OS.h"
+#include "global.h"
+#include "Comm_Manager.h"
+
+class CM_Client : public Comm_Manager
+{
+ // = TITLE
+ // Provides a virtual communcations layer for the client in the
+ // drwho program.
+public:
+ // = Initialization and termination.
+ CM_Client (void);
+ // Constructor.
+
+ virtual ~CM_Client (void);
+ // Destructor.
+
+ virtual int mux (char *packet, int &packet_length) = 0;
+ virtual int demux (char *packet, int &packet_length) = 0;
+ virtual int open (short port_number);
+ virtual int receive (int timeout = 0);
+ virtual int send (void);
+
+private:
+ fd_set read_fd_;
+ timeval time_out_;
+ timeval *top_;
+};
+
+#endif /* _CM_CLIENT_H */
diff --git a/apps/drwho/CM_Server.cpp b/apps/drwho/CM_Server.cpp
new file mode 100644
index 00000000000..f9306553269
--- /dev/null
+++ b/apps/drwho/CM_Server.cpp
@@ -0,0 +1,85 @@
+// $Id$
+#include "global.h"
+#include "Options.h"
+#include "CM_Server.h"
+
+/* Creates and binds a UDP socket... */
+
+int
+CM_Server::open (short port_number)
+{
+ int max_packet_size = UDP_PACKET_SIZE;
+
+ if ((this->sokfd = socket (PF_INET, SOCK_DGRAM, 0)) < 0)
+ return -1;
+
+ bzero (&this->sin, sizeof this->sin);
+ this->sin.sin_family = AF_INET;
+ this->sin.sin_port = htons (port_number);
+ this->sin.sin_addr.s_addr = INADDR_ANY;
+
+ /* This call fails if an rflo daemon is already running. */
+ if (bind (this->sokfd, (sockaddr *) &this->sin, sizeof this->sin) < 0)
+ return -1;
+
+#ifndef i386
+ /* Allow for very large datagrams. */
+
+ if (setsockopt (this->sokfd, SOL_SOCKET, SO_SNDBUF, (char *) &max_packet_size, sizeof max_packet_size) < 0)
+ return -1;
+#endif
+
+ return 1;
+}
+
+int
+CM_Server::receive (int)
+{
+ /* SUPPRESS 175 */
+ int sin_len = sizeof this->sin;
+ int n;
+
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "waiting for client to send...\n");
+
+ if ((n = recvfrom (this->sokfd, this->recv_packet, UDP_PACKET_SIZE, 0, (sockaddr *) &this->sin, &sin_len)) < 0)
+ return -1;
+
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "receiving from client host %s\n", inet_ntoa (this->sin.sin_addr));
+
+ if (this->demux (this->recv_packet, n) < 0)
+ return -1;
+
+ return 1;
+}
+
+int
+CM_Server::send (void)
+{
+ /* SUPPRESS 175 */
+ int packet_length = 0;
+
+ if (this->mux (this->send_packet, packet_length) < 0)
+ return -1;
+
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "sending to client host %s\n", inet_ntoa (this->sin.sin_addr));
+
+ if (sendto (this->sokfd, this->send_packet, packet_length, 0, (sockaddr *) &this->sin, sizeof this->sin) < 0)
+ return -1;
+
+ return 1;
+}
+
+#ifndef __OPTIMIZE__
+CM_Server::CM_Server (void)
+{}
+
+CM_Server::~CM_Server (void)
+{
+ if (Options::get_opt (Options::DEBUG))
+ fprintf (stderr, "CM_Server\n");
+ close (this->sokfd);
+}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/CM_Server.h b/apps/drwho/CM_Server.h
new file mode 100644
index 00000000000..db0cea2a33f
--- /dev/null
+++ b/apps/drwho/CM_Server.h
@@ -0,0 +1,41 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides a virtual communcations layer for the server in the drwho
+ program. */
+
+#ifndef _CM_SERVER_H
+#define _CM_SERVER_H
+
+#include "Options.h"
+#include "ace/OS.h"
+#include "global.h"
+#include "Comm_Manager.h"
+
+class CM_Server : public Comm_Manager
+{
+public:
+ CM_Server (void);
+ virtual ~CM_Server (void);
+
+ virtual int open (short port_number);
+ virtual int receive (int timeout = 0);
+ virtual int send (void);
+ virtual int mux (char *packet, int &packet_length) = 0;
+ virtual int demux (char *packet, int &packet_length) = 0;
+};
+
+#ifdef __OPTIMIZE__
+inline
+CM_Server::CM_Server (void)
+{}
+
+inline
+CM_Server::~CM_Server (void)
+{
+ if (Options::get_opt (Options::DEBUG))
+ fprintf (stderr, "CM_Server\n");
+ close (this->sokfd);
+}
+#endif /* __OPTIMIZE__ */
+#endif _CM_SERVER_H
diff --git a/apps/drwho/ChangeLog b/apps/drwho/ChangeLog
new file mode 100644
index 00000000000..f3f89ee2764
--- /dev/null
+++ b/apps/drwho/ChangeLog
@@ -0,0 +1,239 @@
+Sun Sep 6 22:48:52 1998 Douglas C. Schmidt <schmidt@tango.cs.wustl.edu>
+
+ * Replaced all Str::*() methods with the new ACE::*() methods,
+ which are more "standard".
+
+ * Began to work on drwho after a 5 year absence...
+
+Sun Feb 14 16:13:10 1993 Douglas C. Schmidt (schmidt at net1.ics.uci.edu)
+
+ * Yow. Once again back at work... This time I fixed things up so
+ that the release compiles properly with Solaris 2.1 C++, g++
+ 2.3.3, and the Sun C++ compiler on Sun OS 4.1.x. To do this I
+ had to change the user-defined memory allocator somewhat, since
+ the Sun C++ compiler was using the global NEW operator to
+ allocate pools of memory behind my back... Naturally, this
+ reaked havoc with the existing version in the server, which
+ returns all the allocated memory to the free list once a request
+ is satisfied. In addition, g++ had a weird multiple
+ inheritance/pure virtual function bug that I fixed by reordering
+ certain pure virtual functions. Oh what fun... ;-) Anyhow,
+ everything is now back in running order!
+
+Sun Dec 6 16:13:21 1992 Douglas C. Schmidt (schmidt at net1.ics.uci.edu)
+
+ * Yow, well, after about 8 months of total neglect I'm finally
+ back at work on this program! The current changes I did today
+ involved getting drwho to compile with g++ 2.3.2. This required
+ a couple of small work arounds in the source code due to bugs,
+ but hey, I guess it is better than nothing right?!
+
+ Also, I had to fix a couple of places where I didn't correctly
+ initialize static variables (the compiler implementations have
+ changed since last year obviously). Also, I've changed a couple
+ of the default server hosts to reflect the fascist policies of
+ our support group ;-) (I've no longer got access to certain
+ servers...)
+
+ Anyhow, I think drwho is once again running with g++, so now I
+ can hand the release over to Ericka... ;-)
+
+Wed May 6 23:12:02 1992 Douglas C. Schmidt (schmidt at net4.ics.uci.edu)
+
+ * There is something horribly wrong with g++ 2.1. Therefore, I
+ had to make a couple of changes in the pmc-rusers.C and
+ pm-client.C files in order to make the blasted thing compile
+ when I had pointers to member functions... Make sure to change
+ this back when g++ is fixed...
+
+Tue Feb 4 11:23:12 1992 Douglas C. Schmidt (schmidt at net6.ics.uci.edu)
+
+ * The blasted program was crashing when there were consecutive
+ newlines in the input file. I fixed
+ File_Manager::get_login_and_real_name and
+ File_Manager::open_friends_file so that they detect and skip
+ over these consecutive newlines.
+
+Thu Nov 21 21:55:00 1991 Douglas C. Schmidt (schmidt at net6.ics.uci.edu)
+
+ * Make the time that drwho uses to consider a host idle be a
+ command-line parameter.
+
+Wed Nov 13 14:24:40 1991 Douglas C. Schmidt (schmidt at bastille.ics.uci.edu)
+
+ * Something else that ought to be done:
+
+ Add a flag to the -R option that allows the hostname to be
+ printed using the internet address and/or the hostname...
+
+Sat Nov 9 13:45:30 1991 Douglas C. Schmidt (schmidt at bastille.ics.uci.edu)
+
+ * Added zillions more changes yet again. We now have an rusers
+ compatibility mode (-R), to go along with the -a, -w, and
+ default (flo) options.
+
+ * Changed the -w option so that it only returns the name of the
+ host machine where the user is logged in. This way, I can say:
+
+ % talk schmidt@`drwho -w schmidt`
+ % rsh `drwho -w schmidt` w
+
+ etc... ;-)
+
+ * Added support for the -L option (print using login name rather
+ than real name). Also added support for the -l option (print
+ out verbosely, a la ls -l!).
+
+Sun Oct 27 21:32:15 1991 Douglas C. Schmidt (schmidt at bastille.ics.uci.edu)
+
+ * Need to complete the -s and -S options to support sorting the
+ output by login name and real name, respectively... In order to
+ support the '*' indication with this scheme we probably need to
+ lists, one for active and one for inactive users!
+
+Tue Oct 22 00:13:21 1991 Douglas C. Schmidt (schmidt at net6.ics.uci.edu)
+
+ * Make another zillion changes...
+
+Sun Oct 20 21:35:24 1991 Douglas C. Schmidt (schmidt at net6.ics.uci.edu)
+
+ * Added support for the -p option to allow setting the client and
+ server port number from the command-line.
+
+ * Things done so far:
+
+ * Owen also wants an new rflo feature (done)
+
+ I also want a version that given a command like:
+
+ whereis omalley
+
+ would return the login where that login is active if there is
+ one (ie. omalley@zola). Then you could have commands like:
+
+ talk `whereis omalley`
+
+ that would find where I am and try to talk to me there.
+
+ * Another neat addition would be: have an option (e.g., `-a') so
+ that rflo would return *all* the users logged in and then look
+ up their names using the yp passwd stuff! (partially done, but
+ not very elegantly yet...). (done)
+
+ * Make the port number a command-line option... (done)
+
+ * we also need think about how to incorporate inheritance and
+ dynamic binding into this thang (probably it can be used for
+ the local/remote split, and also perhaps for the
+ friends/everyone split (see below)). (done)
+
+ * Fix up the options stuff wrt the -F option etc... (done)
+
+ * Have I fixed the is_active shit? (done)
+
+ * we need a "message abstraction" that abstracts away from the
+ details of packets protocols and remote operations protocols.
+ (done).
+
+ * Note, should make an option so we could read the names of the
+ hosts to query from a file... (done)
+
+Fri Oct 18 16:17:39 1991 Douglas C. Schmidt (schmidt at net6.ics.uci.edu)
+
+ * I've made countless changes...
+
+Wed Oct 16 17:42:40 1991 Douglas C. Schmidt (schmidt at net6.ics.uci.edu)
+
+ * Undid the message manager abstraction and merged it in with the
+ Friend_Manager client and server. This really cleans up the
+ interface!
+
+ * Yow, make zillions of important changes to make the
+ client/server split more explicit... Now the Friend_Manager is
+ split into client and server, the message manager is split, and
+ the communications manager is also split. Each file is much
+ smaller and easier to understand!
+
+Mon Oct 14 18:36:55 1991 Douglas C. Schmidt (schmidt at net1.ics.uci.edu)
+
+ * Added support for the -h and -? options, that print out a long
+ and short usage message, respectively.
+
+Tue Oct 1 09:28:29 1991 Douglas C. Schmidt (schmidt at net4.ics.uci.edu)
+
+ * The -a option works a great deal better too... I added a check
+ in the File_Manager::open_passwd_file routine to strip off the
+ extra subfields in the pw_gecos field, since this info isn't
+ really very useful and makes the "real name" field too long!
+
+ * Added some extra stuff to the Comm_Manager so that I could
+ change the max size of the UDP datagrams that are passed around.
+ As it turns out, I don't really need to do this, but it is more
+ robust this way...
+
+Thu Sep 26 14:00:45 1991 Douglas C. Schmidt (schmidt at net4.ics.uci.edu)
+
+ * Make sun3 and sun4 subdirectories to help the build process!
+
+ * Changed the UDP port number from 12346 to 12344 so I wouldn't
+ collide with Owen!
+
+ * There is a weird bus error problem on the sun 4s... Hum...
+
+ * Yow, got everything working again...
+
+ * Still to do:
+
+ * Think about fixing the -f option to work correctly for
+ *relative* filenames...
+
+ * Make UDP_BUFFER_SIZE a command-line option...
+
+ * Modify server.C to be started by inetd.
+
+ * For -a option... if they are a friend, use the name from
+ .friend.dta otherwise use the name from the passwd file.
+
+ * Don't forget about:
+
+ delete Friend_Manager::friend_record;
+ delete Friend_Manager::sorted_record;
+
+ Need to figure out a good way to deal with this!
+
+Mon Sep 23 16:09:46 1991 Douglas C. Schmidt (schmidt at net4.ics.uci.edu)
+
+ * Added a neat feature that now allows the user to specify which
+ hosts to examine by specifying an option ('-F') on the
+ command-line that reads the contents of that file and inserts it
+ into the list of files.
+
+Wed Sep 18 10:46:41 1991 Douglas C. Schmidt (schmidt at bastille.ics.uci.edu)
+
+ * We need to make all the interfaces throughout rflo much more
+ object-oriented, e.g.:
+
+ * Made a host-manager abstraction to handle all the host
+ machine related operations. This makes the options stuff
+ *much* cleaner!
+
+ * Make rflo compile with g++ 1.37.2! Now it compiles with cfront
+ 2.0, Saber C++ 1.0.1 and g++-1.39.0 and g++-1.37.2.
+
+Tue Sep 17 19:02:47 1991 Douglas C. Schmidt (schmidt at net4.ics.uci.edu)
+
+ * Started merging in the stuff Owen did. I'm trying to maintain a
+ consistent programming style... The Owen stuff adds support for
+ timeouts and fixes problems with returning a count of the number
+ of friends!
+
+Wed Sep 4 10:14:51 1991 Douglas C. Schmidt (schmidt at net4.ics.uci.edu)
+
+ * Things to do:
+
+ * Add comprehensive daemon support for server.C.
+ * Add timeout stuff in case hosts are down!
+ * Talk to support about making a standard daemon.
+ * Fix the problem with returning the number of friends.
+
+
diff --git a/apps/drwho/Comm_Manager.h b/apps/drwho/Comm_Manager.h
new file mode 100644
index 00000000000..98f33a28d39
--- /dev/null
+++ b/apps/drwho/Comm_Manager.h
@@ -0,0 +1,26 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides a virtual communcations layer for the drwho program. */
+
+#ifndef _COMM_MANAGER_H
+#define _COMM_MANAGER_H
+
+#include "ace/OS.h"
+#include "global.h"
+
+class Comm_Manager
+{
+protected:
+ char recv_packet[UDP_PACKET_SIZE];
+ char send_packet[UDP_PACKET_SIZE];
+ sockaddr_in sin;
+ int sokfd;
+
+ virtual int mux (char *packet, int &packet_length) = 0;
+ virtual int demux (char *packet, int &packet_length) = 0;
+ virtual int open (short port_number) = 0;
+ virtual int receive (int timeout = 0) = 0;
+ virtual int send (void) = 0;
+};
+#endif _COMM_MANAGER_H
diff --git a/apps/drwho/Drwho_Node.cpp b/apps/drwho/Drwho_Node.cpp
new file mode 100644
index 00000000000..7b3cb3867a5
--- /dev/null
+++ b/apps/drwho/Drwho_Node.cpp
@@ -0,0 +1,87 @@
+// $Id$
+#include "Drwho_Node.h"
+
+#ifndef __OPTIMIZE__
+/* Create a Drwho_Node object */
+
+Drwho_Node::Drwho_Node (char *h_name, Drwho_Node *n)
+ : next (n), inactive_count (0), active_count (0), key_name1 (h_name), key_name2 (0)
+{}
+
+Drwho_Node::Drwho_Node (void)
+ : next (0), inactive_count (0), active_count (0), key_name1 (0), tty_name (0), idle_time (0), key_name2 (0)
+{}
+
+char *
+Drwho_Node::get_login_name (void)
+{
+ return this->key_name1;
+}
+
+char *
+Drwho_Node::set_login_name (char *str)
+{
+ return this->key_name1 = str;
+}
+
+char *
+Drwho_Node::get_real_name (void)
+{
+ return this->key_name2;
+}
+
+char *
+Drwho_Node::set_real_name (char *str)
+{
+ return this->key_name2 = str;
+}
+
+char *
+Drwho_Node::get_host_name (void)
+{
+ return this->key_name1;
+}
+
+char *
+Drwho_Node::set_host_name (char *str)
+{
+ return this->key_name1 = str;
+}
+
+int
+Drwho_Node::get_active_count (void)
+{
+ return this->active_count;
+}
+
+int
+Drwho_Node::get_inactive_count (void)
+{
+ return this->active_count;
+}
+
+int
+Drwho_Node::set_active_count (int count)
+{
+ return this->active_count = count;
+}
+
+int
+Drwho_Node::set_inactive_count (int count)
+{
+ return this->inactive_count = count;
+}
+
+int
+Drwho_Node::set_idle_time (int it)
+{
+ return this->idle_time = it;
+}
+
+int
+Drwho_Node::get_idle_time (void)
+{
+ return this->idle_time;
+}
+#endif /* __OPTIMIZE__ */
+
diff --git a/apps/drwho/Drwho_Node.h b/apps/drwho/Drwho_Node.h
new file mode 100644
index 00000000000..e067525500d
--- /dev/null
+++ b/apps/drwho/Drwho_Node.h
@@ -0,0 +1,121 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Stores information about a host for a specific friend. */
+
+#ifndef _DRWHO_NODE_H
+#define _DRWHO_NODE_H
+
+#include "ace/OS.h"
+#include "global.h"
+
+struct Drwho_Node
+{
+ char *key_name1;
+ char *key_name2;
+ char *tty_name;
+ int idle_time;
+ int active_count;
+ int inactive_count;
+ Drwho_Node *next;
+
+ Drwho_Node (char *host, Drwho_Node *next);
+ Drwho_Node (void);
+ int get_active_count (void);
+ int get_inactive_count (void);
+ int set_active_count (int count);
+ int set_inactive_count (int count);
+ int set_idle_time (int idle_time);
+ int get_idle_time (void);
+ char *get_host_name (void);
+ char *set_host_name (char *str);
+ char *get_login_name (void);
+ char *set_login_name (char *);
+ char *get_real_name (void);
+ char *set_real_name (char *);
+};
+
+#ifdef __OPTIMIZE__
+inline
+Drwho_Node::Drwho_Node (char *h_name, Drwho_Node *n)
+ : next (n), inactive_count (0), active_count (0), key_name1 (h_name), key_name2 (0)
+{}
+
+inline
+Drwho_Node::Drwho_Node (void)
+ : next (0), inactive_count (0), active_count (0), key_name1 (0), tty_name (0), idle_time (0), key_name2 (0)
+{}
+
+inline char *
+Drwho_Node::get_login_name (void)
+{
+ return this->key_name1;
+}
+
+inline char *
+Drwho_Node::set_login_name (char *str)
+{
+ return this->key_name1 = str;
+}
+
+inline char *
+Drwho_Node::get_real_name (void)
+{
+ return this->key_name2;
+}
+
+inline char *
+Drwho_Node::set_real_name (char *str)
+{
+ return this->key_name2 = str;
+}
+
+inline char *
+Drwho_Node::get_host_name (void)
+{
+ return this->key_name1;
+}
+
+inline char *
+Drwho_Node::set_host_name (char *str)
+{
+ return this->key_name1 = str;
+}
+
+inline int
+Drwho_Node::get_active_count (void)
+{
+ return this->active_count;
+}
+
+inline int
+Drwho_Node::get_inactive_count (void)
+{
+ return this->inactive_count;
+}
+
+inline int
+Drwho_Node::set_active_count (int count)
+{
+ return this->active_count = count;
+}
+
+inline int
+Drwho_Node::set_inactive_count (int count)
+{
+ return this->inactive_count = count;
+}
+
+inline int
+Drwho_Node::set_idle_time (int idle_time)
+{
+ return this->idle_time = idle_time;
+}
+
+inline int
+Drwho_Node::get_idle_time (void)
+{
+ return this->idle_time;
+}
+#endif /* __OPTIMIZE__ */
+#endif /* _DRWHO_NODE_H */
diff --git a/apps/drwho/EXAMPLE b/apps/drwho/EXAMPLE
new file mode 100644
index 00000000000..a8ef4b12fe7
--- /dev/null
+++ b/apps/drwho/EXAMPLE
@@ -0,0 +1,311 @@
+Hi,
+
+ I'm in the finishing stages of writing a program called
+'drwho' (short for "Distributed RWHO"), that gets around certain rwho
+limitations, adds functionality, and also prints a much prettier
+listing of who's logged in around a network. Here's a short blurb
+describing the program if you'd like to try it out (don't worry, no
+Trojan horses... ;-)).
+
+ The C++ source is in ~schmidt/languages/C++/drwho. It is a
+tour de force of Object-Oriented Design and Programming!!!
+
+ Hope you like it!
+
+ Doug
+
+----------------------------------------
+p.s. Here are some samples. If you'd like to find out who's logged
+in around here, try the following commands:
+
+# Prints out the help file
+
+% ~schmidt/bin/sun4/drwho -r -h
+usage: drwho
+-? prints a short usage message
+-A append the following hostname to the list of predefined hostnames.
+-a return information on *all* users remotely logged in (uses yp passwd).
+-b run the server in the background (i.e., as a daemon).
+-d turn on debugging.
+-F use the following file contents to initialize the host list.
+-f use the following file contents to initialize the friends database.
+-H use the following hostname as part of the new list of hostnames.
+ this option overwrites the existing default names).
+-h print a long usage message.
+-L print the login name rather than the real name (which is the default).
+-l print information in long format (works for all protocols).
+-p set the port number (server must correspond).
+-R print info using the rusers format.
+-r do the remote lookups (i.e., local operations are the default).
+-t set the amount of time we wait for servers to timeout.
+-w return information on just one user.
+----------------------------------------
+
+# Find out where a particular person is logged in:
+
+% ~schmidt/bin/sun4/drwho -r -w brodbeck
+chateau
+
+This is useful for remote commands that require a hostname, e.g.:
+
+% talk brodbeck@`drwho -r -w brodbeck`
+
+or
+
+% rsh `drwho-client -w brodbeck` "ps -aux | egrep -v 'root|schmidt'"
+USER PID %CPU %MEM SZ RSS TT STAT START TIME COMMAND
+brodbeck 21991 0.0 0.0 108 0 co IW Nov 8 0:10 /usr/bin/X11R4/xclock -r
+bin 46 0.0 0.0 36 0 ? IW Oct 15 0:01 ypbind
+brodbeck 21907 0.0 0.0 216 0 co IW Nov 8 0:00 -tcsh (tcsh)
+brodbeck 22000 0.0 0.0 224 0 p1 IW Nov 8 0:01 -csh (tcsh)
+brodbeck 21973 0.0 1.9 864 360 co S Nov 8 2:42 /usr/bin/X11R4/Xsun :0 -
+brodbeck 21998 0.0 0.0 212 0 p0 IW Nov 8 0:00 -csh (tcsh)
+brodbeck 22001 0.0 0.0 224 0 p3 IW Nov 8 0:02 -csh (tcsh)
+brodbeck 22783 0.0 1.4 200 264 p3 S 14:07 0:00 vi one_page_summary
+brodbeck 21972 0.0 0.0 40 0 co IW Nov 8 0:00 /usr/bin/X11/xinit -- -l
+brodbeck 22803 0.0 0.0 40 0 p1 IW 14:12 0:00 more inbox/37
+brodbeck 21979 0.0 0.0 112 0 co IW Nov 8 0:00 olwm -3 -f
+brodbeck 21992 0.0 0.5 108 96 co S Nov 8 0:23 /usr/bin/X11R4/xbiff -bg
+brodbeck 21999 0.0 0.0 212 0 p2 IW Nov 8 0:00 -csh (tcsh)
+
+or
+
+% foreach host (`drwho -r -l -w brodbeck`)
+? echo $host
+? rsh $host w | egrep brodbeck
+? end
+----------------------------------------
+
+# Find out which friends are logged in (* means currently active)
+
+% drwho -r -f ~schmidt/.friends.dta
+remote friends logged on
+------------------------
+ Delectable Debi [chateau]
+ Chang-Kai Chek [hera]
+ Gary Gershwin [wagram paris buckaroo ics sherlock]
+ Andrew Harrison [buckaroo laguna ics cthulu]
+ Holly Hocs [jourdain]
+ Dr. Dave [laguna broadway]
+ Sam Horrocks [brochant paris buckaroo liege laguna ics bonnie john-bigboote]
+ Well Hung [net5]
+ Kari Knees [st-michel]
+ Ionas Rex [ics]
+ Dr. Ray [bonnie pan clipperton]
+ Frank Marino [bonnie]
+ David "fine" Levine [trinite dinsdale segur]
+ Clark Kent Madsen [pasteur]
+ Jo Jo Starbuck [segur]
+ Owen O'Palley [dinsdale porte-de-st-ouen]
+ Tim Morgan [glacier buckaroo ics john-parker]
+ Too Thieu [valentine]
+ Alex Nicolau [ics ck7]
+ Golden Bear [zola bear]
+ David Ruby [ics ocean steppingstone]
+ Elke Summers [aardvark]
+*Doug O'las [pasteur beaver* net6*(2) net4]
+ Karl Marx Schwamb [abp]
+ Rick Selby [louvre]
+ this->self [pasteur bugfix]
+ Sheba [cardinal]
+ Tatsuda [valentine]
+ Cindy Twiddle [alexandre-dumas]
+*Vanessa Redgrave [bonnie*(2)]
+ Zippy Ziv [pigalle trinite]
+------------------------
+friends: 5 users: 168
+
+----------------------------------------
+
+# Find out everyone who is logged in everywhere!
+
+% drwho -r -a
+remote users logged on
+------------------------
+ Barbara Weisenfluh [sunshine]
+ Jon Krause [laguna]
+ David Kramer [olympus]
+ Cindy Tittle Moore [alexandre-dumas]
+ Karl Schwamb [abp]
+*Anh Hoang Tran [bonnie*]
+ Adam Uthcritam [buckaroo]
+ Harry Yessayan [chapelle]
+ Girish Kotmire [legion]
+*Udhw68k [ics*]
+ Ruben Ernesto Ortega [simplon]
+ Jeanne Pickering [poisson]
+ Hai-Geng Wang [ics buckaroo esp cy4]
+ Keith A. Marino [bonnie]
+ cinouye [bonnie]
+ Mark Rentmeesters [laguna siam]
+ Heping He [crimee monceau]
+*David Kakichi Kauahao Nitta [bonnie*]
+ Umesh Krishnaswamy [calliope]
+ David Kolson [purple]
+ Eddie Schwalb [cliff ocean broadway]
+ Phillip Raymond Colline [bonnie]
+ Scott Erickson [ics paris wagram buckaroo sherlock]
+ Doris Tonne [bonnie]
+ Alan Keren [brooks]
+ Debra Brodbeck [chateau]
+*Uocsqnt [ics*]
+ Chung Ng [liege trocadero]
+*John Romine [bonnie ics london woolamaloo paris buckaroo*(1) philosophy yoyodyne beaver]
+ Lisa Tellier [coyote]
+ Merri Naka [perfect-tommy]
+ David Eppstein [wormwood]
+ Heather Ross [bonnie ics paris john-yaya]
+*Gary Hiromi Nakamura [bonnie*]
+ James Kipps [ocean]
+ Kamal Ali [pan ci4 focl]
+ Xiping Song [berault]
+*Up4tusti [ics*]
+ Robert Allen Monroe [bonnie]
+ Craig Snider [gobelins]
+ Jose C. Barrios [chatelet]
+ Lynn Stauffer [cg3]
+*Alastair Milne [ics*]
+ David Levine [trinite dinsdale segur]
+ Operator [laguna bonnie ics woolamaloo paris rome cecil buckaroo beanie philosophy]
+ Mary Franks [john-starbird]
+ Roni Potasman [esp enterprise]
+*jli1 [bonnie*]
+ Wendy Lasher [voltaire]
+ John King [ics]
+*skeung [bonnie*]
+ David Harnick-Shapiro [laguna bonnie ics woolamaloo glacier paris buckaroo beanie john-littlejohn john-yaya esp valentine]
+ Dennis Kibler [turing]
+*Vanessa Yun-Yin Yuan [bonnie*(2)]
+ Tedd Hadley [etoile]
+ Hung Huang [net5]
+ George S. Lueker [john-wood]
+ Rina Dechter [john-grim]
+ Elke A. Rundensteiner [aardvark]
+ Richard Selby [louvre]
+ Thanh Lan Vu [bonnie]
+*Steven Lafayette Smith [bonnie*]
+ Owen O'Malley [dinsdale porte-de-st-ouen]
+*Dennis Troup [sainte-denis*(1)]
+ Alex Odyniec [ics]
+ Patrick Young [elysees]
+ Lubomir Bic [cj2]
+*ryoshii [ics*]
+ Carmen Mendoza [anniebell]
+ Gregory Alan Bolcer [liege javel crimee]
+*El Fattah [trix*(1)]
+*Mei-Fan Chou [bonnie*]
+ X-MAN [net1]
+ Fei York Yee [bonnie]
+ Nikil Dutt [ics synthesis]
+ Sam Horrocks [laguna liege bonnie ics paris buckaroo brochant john-bigboote]
+ Alfred Bork [idyllwild]
+*M i n h [bonnie*]
+ Ray Klefstad [bonnie pan clipperton]
+ Thieu Q. Nguyen [valentine]
+ Debra Richardson [zola bear]
+*sjalali [bonnie*]
+ R. Kent Madsen [pasteur]
+*Donna Rae Love [bonnie*]
+ Brian Christopher Pitterle [fdr]
+*Shilpa V. Shukla [bonnie*]
+ Earl Wayne Jr. Hood [bonnie]
+ Young Kim [myrtle]
+ Stephanie Leif Aha [cardinal]
+*Steven Daniel Wallace [bonnie*]
+ Szu-Ching Wang [bonnie]
+ Patrick Murphy [focl]
+ Paul O'Rorke [ci2]
+ Craig Alan Macfarlane [liege chateau-rouge]
+ Mats Heimdahl [duroc]
+ CF Engineer [ics]
+*dialup [ics*]
+ Ki C. Kim [cy2]
+ Hadar Ziv [pigalle trinite]
+ Software Testing group [liege siam]
+ David Ruby [ics ocean steppingstone]
+*Stephen Te-Lung Chen [bonnie*]
+ Michael Dillencourt [cubes]
+*hlin1 [bonnie*]
+ Andrew Harrison [laguna ics buckaroo cthulu]
+ Ken Anderson [mabillon]
+ Alex Nicolau [ics ck7]
+*John Richard Place [bonnie*(2)]
+*Douglas C. Schmidt [pasteur beaver* net6*(2) net4]
+ Holly Hildreth [jourdain]
+ Kari Forester [st-michel]
+ Joy Schuler [scooter]
+ Michael Pazzani [pan]
+ Kazushige Shimono [valentine]
+ Joan Mahoney [segur]
+ John Self [pasteur bugfix]
+ Steve Morris [tweezer]
+ Isaac D Scherson [zeus]
+*Dongpei Zhuo [bonnie*(2)]
+ Pat Harris [surrey]
+*Robert Steven Zucker [siam*]
+ Tatsuya Suda [valentine]
+ Jeff Erickson [madeleine]
+ David A. Honig [laguna broadway]
+ Chi-Kai Chien [hera]
+ Dan Gajski [ics]
+*Steven Novack [snowball*(1)]
+*Chung Tak Wong [bonnie*(1)]
+ Tim Morgan [ics glacier buckaroo john-parker]
+*Stephen James Martin [bonnie*]
+ Billie Bozarth [etoile jasmin]
+ You have new mail. [liege dinsdale ternes]
+*Chiharu Sano [bonnie*]
+ Fran Paz [willis]
+------------------------
+friends: 37 users: 163
+----------------------------------------
+
+# Print out all machines and who is logged into each one
+
+% drwho -R -l
+drwho-client -R -L
+beanie operator
+crimee harrison hhe
+siam mrentme
+alexandre-dumas tittle
+avron heimdahl
+cecil operator
+elysees pyoung
+pasteur madsen*(1)
+sainte-denis troup
+gobelins snider
+bugfix self
+mabillon kanderso*(3)
+buckaroo operator david sam authcrit wang harrison jromine morgan yin
+rome operator sam
+paris operator jromine sam david heather
+chateau brodbeck*(1)
+wagram sam
+simplon rortega
+jourdain hildreth
+javel gbolcer
+bastille self schmidt*(1)
+monceau hhe
+glacier hhe david morgan
+porte-de-st-ouen omalley
+berault song
+laguna operator harrison sam david jromine jkrause mrentme kanderso*(1)
+jasmin bozarth
+chateau-rouge cmacfarl
+zola sam omalley
+invalides mrentme
+london operator jromine
+brochant gbolcer
+rennes steph
+pigalle ziv
+aardvark rundenst
+chapelle yessayan
+cad jianl*(1)
+liege cmacfarl kari aporter yessayan rzucker sam
+woolamaloo operator
+st-michel kari
+segur jmahoney
+philosophy operator
+sablon rundenst
+dinsdale cmacfarl yessayan sam
+----------------------------------------
diff --git a/apps/drwho/File_Manager.cpp b/apps/drwho/File_Manager.cpp
new file mode 100644
index 00000000000..c93b6398a50
--- /dev/null
+++ b/apps/drwho/File_Manager.cpp
@@ -0,0 +1,162 @@
+// $Id$
+#include "global.h"
+#include "ace/Mem_Map.h"
+#include "File_Manager.h"
+
+/* Initialize statics... */
+
+char *File_Manager::current_ptr = 0;
+int File_Manager::number_of_friends = 0;
+int File_Manager::max_key_length = 0;
+char *File_Manager::buffer_ptr = 0;
+int File_Manager::buffer_size = 0;
+
+/* Either opens the friends file (if FILE_NAME is not a NULL pointer)
+ or opens up the password file. In either case, the number of
+ entries in the file are returned, i.e., number of friends... */
+
+int
+File_Manager::open_file (char *file_name)
+{
+ return file_name == '\0'
+ ? File_Manager::open_passwd_file ()
+ : File_Manager::open_friends_file (file_name);
+}
+
+/* Returns the next LOGIN_NAME and REAL_NAME from the file. */
+
+int
+File_Manager::get_login_and_real_name (char *&login_name, char *&real_name)
+{
+ char *buf_ptr = File_Manager::current_ptr;
+
+ login_name = buf_ptr;
+
+ /* Skip to the end of the login name. */
+
+ while (isalnum (*buf_ptr))
+ buf_ptr++;
+
+ *buf_ptr++ = '\0';
+
+ /* Now skip over white space to *start* of real name! */
+
+ while (isspace (*buf_ptr) || *buf_ptr == '\0')
+ buf_ptr++;
+
+ real_name = buf_ptr;
+
+ while (*buf_ptr++ != '\n')
+ ;
+
+ /* Clear the trailing blanks and junk. */
+
+ for (char *tmp_ptr = buf_ptr - 1; isspace (*tmp_ptr); tmp_ptr--)
+ *tmp_ptr = '\0';
+
+ /* Skip over consecutive blank lines. */
+
+ while (*buf_ptr == '\n')
+ buf_ptr++;
+
+ File_Manager::current_ptr = buf_ptr;
+ return 1;
+}
+
+/* Open up the yp passwd file and slurp all the users in! */
+
+int
+File_Manager::open_passwd_file (void)
+{
+ FILE *fp;
+ char *file_name;
+ struct passwd *pwent;
+
+ file_name = tmpnam ((char *) 0);
+
+ if ((fp = fopen (file_name, "w")) == 0)
+ return -1;
+
+ for (setpwent (); (pwent = getpwent ()) != 0; )
+ if (*pwent->pw_gecos != '\0')
+ {
+ char *cp = strchr (pwent->pw_gecos, ',');
+
+ if (cp != 0)
+ *cp = '\0';
+
+ fprintf (fp, "%-8.8s %s\n", pwent->pw_name, pwent->pw_gecos);
+ File_Manager::number_of_friends++;
+ }
+
+ endpwent ();
+
+ fclose (fp);
+
+ ACE_Mem_Map mmap (file_name);
+
+ File_Manager::buffer_ptr = mmap.addr ();
+
+ if (File_Manager::buffer_ptr >= 0)
+ {
+ File_Manager::buffer_size = mmap.size ();
+ File_Manager::current_ptr = File_Manager::buffer_ptr;
+ return File_Manager::number_of_friends;
+ }
+ return -1;
+}
+
+/* This function opens up FILE_NAME and memory maps it in our address space. */
+
+int
+File_Manager::open_friends_file (char *file_name)
+{
+ char *fnp = file_name;
+ int fd;
+
+ /* Split file_name into directory/file_name. */
+
+ if ((fnp = strrchr (file_name, '/')) != 0)
+ fd = open (file_name, O_RDONLY);
+ else
+ {
+ char directory[MAXPATHLEN];
+
+ strcpy (directory, getenv ("HOME"));
+ strcat (directory, "/");
+ strcat (directory, file_name);
+ fd = open (directory, O_RDONLY);
+ }
+
+ /* Do the mmaping if we got the file opened correctly... */
+
+ if (fd < 0)
+ return -1;
+
+ ACE_Mem_Map mmap (fd);
+
+ File_Manager::buffer_ptr = mmap.addr ();
+
+ if (File_Manager::buffer_ptr >= 0)
+ {
+ File_Manager::buffer_size = mmap.size ();
+ File_Manager::current_ptr = File_Manager::buffer_ptr;
+
+ /* Determine how many friends there are by counting the newlines. */
+
+ for (char *cp = File_Manager::buffer_ptr + File_Manager::buffer_size;
+ cp > File_Manager::buffer_ptr
+ ; )
+ if (*--cp == '\n')
+ {
+ File_Manager::number_of_friends++;
+
+ /* Skip consecutive newlines. */
+ while (cp[-1] == '\n')
+ --cp;
+ }
+ return File_Manager::number_of_friends;
+ }
+ return -1;
+}
+
diff --git a/apps/drwho/File_Manager.h b/apps/drwho/File_Manager.h
new file mode 100644
index 00000000000..04dd2e2a099
--- /dev/null
+++ b/apps/drwho/File_Manager.h
@@ -0,0 +1,31 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* This module presents a file ADT for our friends info. */
+
+#ifndef _FILE_MANAGER_H
+#define _FILE_MANAGER_H
+
+#include "ace/OS.h"
+
+class File_Manager
+{
+private:
+ static int number_of_friends;
+ static int max_key_length;
+
+ static char *buffer_ptr;
+ static char *current_ptr;
+ static int buffer_size;
+
+ static int open_friends_file (char *filename);
+ static int open_passwd_file (void);
+
+public:
+ static int open_file (char *filename);
+ static int get_login_and_real_name (char *&login_name, char *&real_name);
+};
+
+#ifdef __OPTIMIZE__
+#endif /* __OPTIMIZE__ */
+#endif /* _FILE_MANAGER_H */
diff --git a/apps/drwho/HT_Client.cpp b/apps/drwho/HT_Client.cpp
new file mode 100644
index 00000000000..b829f1e2a96
--- /dev/null
+++ b/apps/drwho/HT_Client.cpp
@@ -0,0 +1,27 @@
+// $Id$
+#include "new.h"
+#include "HT_Client.h"
+
+/* Insert a KEY_NAME into the hash table, if it doesn't already exist there.
+ What gets returned is a pointer to the node inserted. Note that we do our
+ own memory allocation here... */
+
+Protocol_Record *
+HT_Client::insert (char *key_name, int max_len)
+{
+ /* This is tricky... */
+
+ for (Protocol_Record **frpp = &this->hash_table[this->hash (key_name)];
+ *frpp != 0 && strncmp ((*frpp)->get_login (), key_name, max_len) != 0;
+ frpp = &(*frpp)->next)
+ ;
+
+ if (*frpp == 0)
+ {
+ *frpp = new (PRIVATE_POOL) Protocol_Record (ACE::strnew (key_name), *frpp);
+ this->count++;
+ }
+ return *frpp;
+}
+
+
diff --git a/apps/drwho/HT_Client.h b/apps/drwho/HT_Client.h
new file mode 100644
index 00000000000..0831eb461bb
--- /dev/null
+++ b/apps/drwho/HT_Client.h
@@ -0,0 +1,16 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the client's hash table abstraction. */
+
+#ifndef _HT_CLIENT_H
+#define _HT_CLIENT_H
+
+#include "Hash_Table.h"
+
+class HT_Client : public Hash_Table
+{
+public:
+ virtual Protocol_Record *insert (char *key_name, int max_len = MAXUSERIDNAMELEN);
+};
+#endif /* _HT_CLIENT_H */
diff --git a/apps/drwho/HT_Server.cpp b/apps/drwho/HT_Server.cpp
new file mode 100644
index 00000000000..6b8f0b9d6fe
--- /dev/null
+++ b/apps/drwho/HT_Server.cpp
@@ -0,0 +1,29 @@
+// $Id$
+#include "new.h"
+#include "HT_Server.h"
+
+/* Insert a KEY_NAME into the hash table, if it doesn't already exist there.
+ What gets returned is a pointer to the node inserted. Note that we do our
+ own memory allocation here... */
+
+Protocol_Record *
+HT_Server::insert (char *key_name, int max_len)
+{
+ /* This is tricky... */
+
+ for (Protocol_Record **frpp = &this->hash_table[this->hash (key_name)];
+ *frpp != 0 && strncmp ((*frpp)->get_login (), key_name, max_len) != 0;
+ frpp = &(*frpp)->next)
+ ;
+
+ if (*frpp == 0)
+ {
+ /* Remember, the server must be very careful about stuff it
+ receives from the rwho manager, since it may not be NUL-terminated.
+ That's why we use ACE::strnnew ()... */
+
+ *frpp = new (PRIVATE_POOL) Protocol_Record (ACE::strnnew (key_name, max_len), *frpp);
+ this->count++;
+ }
+ return *frpp;
+}
diff --git a/apps/drwho/HT_Server.h b/apps/drwho/HT_Server.h
new file mode 100644
index 00000000000..a5dc1987a78
--- /dev/null
+++ b/apps/drwho/HT_Server.h
@@ -0,0 +1,16 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the server's hash table abstraction. */
+
+#ifndef _HT_SERVER_H
+#define _HT_SERVER_H
+
+#include "Hash_Table.h"
+
+class HT_Server : public Hash_Table
+{
+public:
+ virtual Protocol_Record *insert (char *key_name, int max_len = MAXUSERIDNAMELEN);
+};
+#endif /* _HT_SERVER_H */
diff --git a/apps/drwho/Hash_Table.cpp b/apps/drwho/Hash_Table.cpp
new file mode 100644
index 00000000000..15fb314370c
--- /dev/null
+++ b/apps/drwho/Hash_Table.cpp
@@ -0,0 +1,90 @@
+// $Id$
+#include "Options.h"
+#include "new.h"
+#include "Hash_Table.h"
+
+Hash_Table::Hash_Table (void): current_ptr (0), current_index (0), hash_table_size (HASH_TABLE_SIZE)
+{
+ this->hash_table = new (PRIVATE_POOL) Protocol_Record *[this->hash_table_size];
+
+ ACE_OS::memset (this->hash_table,
+ 0,
+ this->hash_table_size * sizeof *this->hash_table);
+}
+
+/* Hash using the "Hash PJW" algorithm. */
+
+unsigned int
+Hash_Table::hash (char *s)
+{
+ char *temp = s;
+ unsigned g;
+ unsigned hash = 0;
+
+ for (int i = 0; i < MAXUSERIDNAMELEN && *temp != 0; i++)
+ {
+ hash = (hash << 4) + (*temp++ * 13);
+ if (g = hash & 0xf0000000)
+ {
+ hash ^= (g >> 24);
+ hash ^= g;
+ }
+ }
+
+ return hash % this->hash_table_size;
+}
+
+/* Iterate through the hash table returning one node at a time... */
+
+Protocol_Record *
+Hash_Table::get_next_entry (void)
+{
+ /* Reset the iterator if we are starting from the beginning. */
+
+ if (this->current_index == -1)
+ this->current_index = 0;
+
+ if (this->current_ptr == 0)
+ {
+
+ for (;
+ this->current_index < this->hash_table_size;
+ this->current_index++)
+ if (this->hash_table[this->current_index] != 0)
+ {
+ Protocol_Record *frp = this->hash_table[this->current_index++];
+ this->current_ptr = frp->next;
+ return frp;
+ }
+ this->current_index = -1;
+ return 0;
+ }
+ else
+ {
+ Protocol_Record *frp = this->current_ptr;
+ this->current_ptr = this->current_ptr->next;
+ return frp;
+ }
+}
+
+Protocol_Record *
+Hash_Table::get_each_entry (void)
+{
+ return this->get_next_entry ();
+}
+
+/* Frees up all the dynamic memory in the hash table. */
+
+Hash_Table::~Hash_Table (void)
+{
+ if (Options::get_opt (Options::DEBUG))
+ fprintf (stderr, "disposing Hash_Table\n");
+
+ for (int i = 0; i < this->hash_table_size; i++)
+ for (Protocol_Record *frp = this->hash_table[i]; frp != 0; )
+ {
+ Protocol_Record *tmp = frp;
+ frp = frp->next;
+ }
+
+}
diff --git a/apps/drwho/Hash_Table.h b/apps/drwho/Hash_Table.h
new file mode 100644
index 00000000000..2df70290d31
--- /dev/null
+++ b/apps/drwho/Hash_Table.h
@@ -0,0 +1,30 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides a hash function lookup abstraction for friend records. */
+
+#ifndef _HASH_TABLE_H
+#define _HASH_TABLE_H
+
+#include "Search_Struct.h"
+
+class Hash_Table : public Search_Struct
+{
+protected:
+ enum {HASH_TABLE_SIZE = 500};
+
+ Protocol_Record **hash_table;
+ Protocol_Record *current_ptr;
+ int current_index;
+ int hash_table_size;
+
+ unsigned int hash (char *s);
+
+public:
+ Hash_Table (void);
+ virtual ~Hash_Table (void);
+ virtual Protocol_Record *insert (char *key_name, int max_len = MAXUSERIDNAMELEN) = 0;
+ virtual Protocol_Record *get_next_entry (void);
+ virtual Protocol_Record *get_each_entry (void);
+};
+#endif /* _HASH_TABLE_H */
diff --git a/apps/drwho/Makefile b/apps/drwho/Makefile
new file mode 100644
index 00000000000..ed75fe64512
--- /dev/null
+++ b/apps/drwho/Makefile
@@ -0,0 +1,427 @@
+#----------------------------------------------------------------------------
+# $Id$
+#
+# Makefile for drwho
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Local macros
+#----------------------------------------------------------------------------
+
+SHARED-SRC = Protocol_Manager \
+ Drwho_Node \
+ Rwho_DB_Manager \
+ Multicast_Manager \
+ Protocol_Record \
+ Options \
+ File_Manager \
+ Hash_Table \
+ Binary_Search \
+ Search_Struct \
+ Single_Lookup \
+ new
+SHARED-OBJ = $(addsuffix .o,$(SHARED-SRC))
+
+CLIENT-SRC = PM_Client \
+ CM_Client \
+ HT_Client \
+ BS_Client \
+ PMC_All \
+ PMC_Flo \
+ PMC_Usr \
+ SL_Client \
+ PMC_Ruser \
+ SM_Client \
+ SMR_Client \
+ SML_Client
+CLIENT-OBJ = $(addsuffix .o,$(CLIENT-SRC))
+
+SERVER-SRC = PM_Server \
+ CM_Server \
+ HT_Server \
+ BS_Server \
+ PMS_All \
+ PMS_Flo \
+ PMS_Usr \
+ SL_Server \
+ PMS_Ruser \
+ SM_Server \
+ SMR_Server \
+ SMR_Client
+SERVER-OBJ = $(addsuffix .o,$(SERVER-SRC))
+
+LSRC = client.cpp server.cpp \
+ $(addsuffix .cpp,$(SHARED-SRC)) \
+ $(addsuffix .cpp,$(CLIENT-SRC)) \
+ $(addsuffix .cpp,$(SERVER-SRC))
+
+BIN = drwho-client drwho-server
+BUILD = $(BIN)
+VLDLIBS = $(LDLIBS:%=%$(VAR))
+VBIN = $(BIN:%=%$(VAR))
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(ACE_ROOT)/include/makeinclude/macros.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.common.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.lib.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.local.GNU
+
+#----------------------------------------------------------------------------
+# Local targets
+#----------------------------------------------------------------------------
+
+drwho-client: $(addprefix $(VDIR),$(CLIENT-OBJ)) $(addprefix $(VDIR),$(SHARED-OBJ))
+ $(LINK.cc) $(LDFLAGS) -o $@ $^ $(VLDLIBS)
+
+drwho-server: $(addprefix $(VDIR),$(SERVER-OBJ)) $(addprefix $(VDIR),$(SHARED-OBJ))
+ $(LINK.cc) $(LDFLAGS) -o $@ $^ $(VLDLIBS)
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+
+# DO NOT DELETE THIS LINE -- g++dep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+.obj/client.o .obj/client.so .shobj/client.o .shobj/client.so: client.cpp \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ Options.h SML_Client.h SM_Client.h PM_Client.h Protocol_Manager.h \
+ Search_Struct.h Protocol_Record.h Drwho_Node.h global.h CM_Client.h \
+ Select_Manager.h SML_Server.h SM_Server.h PM_Server.h CM_Server.h \
+ Comm_Manager.h SMR_Client.h
+.obj/server.o .obj/server.so .shobj/server.o .shobj/server.so: server.cpp \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ Options.h SMR_Server.h SM_Server.h PM_Server.h Protocol_Manager.h \
+ Search_Struct.h Protocol_Record.h Drwho_Node.h global.h CM_Server.h \
+ Comm_Manager.h Select_Manager.h
+.obj/Protocol_Manager.o .obj/Protocol_Manager.so .shobj/Protocol_Manager.o .shobj/Protocol_Manager.so: Protocol_Manager.cpp Options.h new.h \
+ Protocol_Manager.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ Search_Struct.h Protocol_Record.h Drwho_Node.h global.h
+.obj/Drwho_Node.o .obj/Drwho_Node.so .shobj/Drwho_Node.o .shobj/Drwho_Node.so: Drwho_Node.cpp Drwho_Node.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ global.h
+.obj/Protocol_Record.o .obj/Protocol_Record.so .shobj/Protocol_Record.o .shobj/Protocol_Record.so: Protocol_Record.cpp Options.h Protocol_Record.h \
+ Drwho_Node.h $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ global.h
+.obj/File_Manager.o .obj/File_Manager.so .shobj/File_Manager.o .shobj/File_Manager.so: File_Manager.cpp global.h \
+ $(ACE_ROOT)/ace/Mem_Map.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ $(ACE_ROOT)/ace/Mem_Map.i \
+ File_Manager.h
+.obj/Hash_Table.o .obj/Hash_Table.so .shobj/Hash_Table.o .shobj/Hash_Table.so: Hash_Table.cpp Options.h new.h Hash_Table.h \
+ Search_Struct.h Protocol_Record.h Drwho_Node.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ global.h
+.obj/Binary_Search.o .obj/Binary_Search.so .shobj/Binary_Search.o .shobj/Binary_Search.so: Binary_Search.cpp Options.h Binary_Search.h
+.obj/Search_Struct.o .obj/Search_Struct.so .shobj/Search_Struct.o .shobj/Search_Struct.so: Search_Struct.cpp Options.h Search_Struct.h \
+ Protocol_Record.h Drwho_Node.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ global.h
+.obj/new.o .obj/new.so .shobj/new.o .shobj/new.so: new.cpp \
+ \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ Options.h
+.obj/CM_Client.o .obj/CM_Client.so .shobj/CM_Client.o .shobj/CM_Client.so: CM_Client.cpp global.h Options.h Multicast_Manager.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ CM_Client.h
+.obj/BS_Client.o .obj/BS_Client.so .shobj/BS_Client.o .shobj/BS_Client.so: BS_Client.cpp Options.h new.h File_Manager.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ BS_Client.h Binary_Search.h
+.obj/SM_Client.o .obj/SM_Client.so .shobj/SM_Client.o .shobj/SM_Client.so: SM_Client.cpp Options.h new.h PMC_All.h PM_Client.h \
+ Protocol_Manager.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ Search_Struct.h Protocol_Record.h Drwho_Node.h global.h PMC_Flo.h \
+ PMC_Usr.h PMC_Ruser.h SM_Client.h CM_Client.h Select_Manager.h
+.obj/SMR_Client.o .obj/SMR_Client.so .shobj/SMR_Client.o .shobj/SMR_Client.so: SMR_Client.cpp Options.h new.h PMC_All.h PM_Client.h \
+ Protocol_Manager.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ Search_Struct.h Protocol_Record.h Drwho_Node.h global.h PMC_Flo.h \
+ PMC_Usr.h PMC_Ruser.h SMR_Client.h SM_Client.h CM_Client.h \
+ Select_Manager.h
+.obj/SML_Client.o .obj/SML_Client.so .shobj/SML_Client.o .shobj/SML_Client.so: SML_Client.cpp Options.h SML_Client.h SM_Client.h \
+ PM_Client.h Protocol_Manager.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ Search_Struct.h Protocol_Record.h Drwho_Node.h global.h CM_Client.h \
+ Select_Manager.h SML_Server.h SM_Server.h PM_Server.h CM_Server.h \
+ Comm_Manager.h
+.obj/CM_Server.o .obj/CM_Server.so .shobj/CM_Server.o .shobj/CM_Server.so: CM_Server.cpp global.h Options.h CM_Server.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ Comm_Manager.h
+.obj/BS_Server.o .obj/BS_Server.so .shobj/BS_Server.o .shobj/BS_Server.so: BS_Server.cpp BS_Server.h Binary_Search.h new.h
+.obj/SM_Server.o .obj/SM_Server.so .shobj/SM_Server.o .shobj/SM_Server.so: SM_Server.cpp new.h Options.h PMS_All.h PM_Server.h \
+ Protocol_Manager.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ Search_Struct.h Protocol_Record.h Drwho_Node.h global.h PMS_Flo.h \
+ PMS_Usr.h PMS_Ruser.h SM_Server.h CM_Server.h Comm_Manager.h \
+ Select_Manager.h
+.obj/SMR_Server.o .obj/SMR_Server.so .shobj/SMR_Server.o .shobj/SMR_Server.so: SMR_Server.cpp Options.h SMR_Server.h SM_Server.h \
+ PM_Server.h Protocol_Manager.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ Search_Struct.h Protocol_Record.h Drwho_Node.h global.h CM_Server.h \
+ Comm_Manager.h Select_Manager.h
+.obj/SMR_Client.o .obj/SMR_Client.so .shobj/SMR_Client.o .shobj/SMR_Client.so: SMR_Client.cpp Options.h new.h PMC_All.h PM_Client.h \
+ Protocol_Manager.h \
+ $(ACE_ROOT)/ace/OS.h \
+ $(ACE_ROOT)/ace/inc_user_config.h \
+ $(ACE_ROOT)/ace/config.h \
+ $(ACE_ROOT)/ace/config-g++-common.h \
+ $(ACE_ROOT)/ace/streams.h \
+ $(ACE_ROOT)/ace/Basic_Types.h \
+ $(ACE_ROOT)/ace/Basic_Types.i \
+ $(ACE_ROOT)/ace/OS.i \
+ $(ACE_ROOT)/ace/Trace.h \
+ $(ACE_ROOT)/ace/Log_Msg.h \
+ $(ACE_ROOT)/ace/Log_Record.h \
+ $(ACE_ROOT)/ace/ACE.h \
+ $(ACE_ROOT)/ace/ACE.i \
+ $(ACE_ROOT)/ace/Log_Priority.h \
+ $(ACE_ROOT)/ace/Log_Record.i \
+ Search_Struct.h Protocol_Record.h Drwho_Node.h global.h PMC_Flo.h \
+ PMC_Usr.h PMC_Ruser.h SMR_Client.h SM_Client.h CM_Client.h \
+ Select_Manager.h
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/apps/drwho/Multicast_Manager.cpp b/apps/drwho/Multicast_Manager.cpp
new file mode 100644
index 00000000000..11a3b5a742f
--- /dev/null
+++ b/apps/drwho/Multicast_Manager.cpp
@@ -0,0 +1,170 @@
+// $Id$
+#include "ACE_Mem_Map.h"
+#include "new.h"
+#include "Multicast_Manager.h"
+#include "global.h"
+
+// Initialize all the static member vars.
+int Multicast_Manager::received_host_count = 0;
+Multicast_Manager::Host_Elem *Multicast_Manager::drwho_list = 0;
+Multicast_Manager::Host_Elem *Multicast_Manager::current_ptr = 0;
+
+/* Names of hosts to query for friend info. */
+char *Multicast_Manager::host_names[] =
+{
+ "mabillon.ics.uci.edu", /* "128.195.14.4", */
+ "beaver.ics.uci.edu", /* "128.195.2.1", */
+ "convention.ics.uci.edu", /* "128.195.8.9", */
+ "valentine.ics.uci.edu", /* "128.200.38.10", */
+ "abp.ics.uci.edu", /* "128.200.39.23", */
+ "cress.ics.uci.edu", /* "128.195.5.8", */
+#if 0
+ "murphy.ics.uci.edu", /* "128.195.4.11", */
+ "madeleine.ics.uci.edu", /* "128.200.32.2", */
+ "liege.ics.uci.edu", /* "128.195.13.1", */
+ "ics.uci.edu", /* "128.195.1.1", */
+ "128.195.10.16", /* vlsi.ics.uci.edu */
+#endif
+ 0 /* The NULL entry... ;-) */
+};
+
+void
+Multicast_Manager::insert_default_hosts (void)
+{
+ /* Enter the static list of hosts into the dynamic table! */
+
+ for (char **np = host_names; *np != 0; np++)
+ Multicast_Manager::add_host (*np);
+}
+
+/* Inserts all the names in FILENAME into the list of hosts to contact. */
+
+int
+Multicast_Manager::insert_hosts_from_file (char *filename)
+{
+ ACE_Mem_Map mmap (filename);
+ char *host_ptr = mmap.addr ();
+
+ if (host_ptr == 0)
+ return -1;
+ else
+ {
+
+ for (char *end_ptr = host_ptr + mmap.size (); host_ptr < end_ptr; )
+ {
+ Multicast_Manager::add_host (host_ptr);
+
+ while (*host_ptr != '\n')
+ host_ptr++;
+
+ *host_ptr++ = '\0';
+ }
+
+ return 0;
+ }
+}
+
+/* Returns the IP host address for the next unexamined host in the list.
+ If no more unexamined hosts remain a 0 is returned, else a 1. */
+
+int
+Multicast_Manager::get_next_host_addr (in_addr &host_addr)
+{
+ for (Multicast_Manager::current_ptr = Multicast_Manager::current_ptr == 0 ? Multicast_Manager::drwho_list : Multicast_Manager::current_ptr->next;
+ Multicast_Manager::current_ptr != 0;
+ Multicast_Manager::current_ptr = Multicast_Manager::current_ptr->next)
+
+ {
+ hostent *hp;
+ char *host_name = Multicast_Manager::current_ptr->host_name;
+
+ if ((hp = Multicast_Manager::get_host_entry (host_name)) == 0)
+ {
+ fprintf (stderr, "%s: host unknown.\n", host_name);
+ continue;
+ }
+
+ Multicast_Manager::received_host_count++;
+ ACE_OS::memcpy (&host_addr,
+ hp->h_addr,
+ sizeof host_addr);
+ ACE_OS::memcpy (&Multicast_Manager::current_ptr->host_addr,
+ hp->h_addr,
+ sizeof host_addr);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* This function attempts to get the internet address for either a
+ hostname or hostnumber. The function makes the simplifying
+ assumption that hostnames begin with an alphabetic character! */
+
+hostent *
+Multicast_Manager::get_host_entry (char *host)
+{
+ static hostent host_entry;
+ auto hostent *hp;
+
+ if (isdigit (*host)) /* IP address. */
+ {
+ unsigned long ia = inet_addr (host);
+
+ hp = ia == (unsigned long) -1 ? 0 : gethostbyaddr ((char *) &ia, sizeof ia, AF_INET);
+ }
+ else /* Host name. */
+ hp = gethostbyname (host);
+
+ return hp == 0 ? 0 : (hostent *) memcpy (&host_entry, hp, sizeof *hp);
+}
+
+/* Adds an additional new host to the list of host machines. */
+
+void
+Multicast_Manager::add_host (char *host_name)
+{
+ Multicast_Manager::drwho_list = new (PRIVATE_POOL) Host_Elem (host_name, Multicast_Manager::drwho_list);
+}
+
+void
+Multicast_Manager::checkoff_host (in_addr host_addr)
+{
+ for (Host_Elem *tmp = Multicast_Manager::drwho_list; tmp != 0; tmp = tmp->next)
+ if (ACE_OS::memcmp (&tmp->host_addr.s_addr,
+ &host_addr.s_addr,
+ sizeof host_addr.s_addr) == 0)
+ {
+ tmp->checked_off = 1;
+ Multicast_Manager::received_host_count--;
+ return;
+ }
+}
+
+int
+Multicast_Manager::get_next_non_responding_host (char *&host_name)
+{
+ for (Multicast_Manager::current_ptr = Multicast_Manager::current_ptr == 0 ? Multicast_Manager::drwho_list : Multicast_Manager::current_ptr->next;
+ Multicast_Manager::current_ptr != 0;
+ Multicast_Manager::current_ptr = Multicast_Manager::current_ptr->next)
+ if (!Multicast_Manager::current_ptr->checked_off)
+ {
+ host_name = Multicast_Manager::current_ptr->host_name;
+ return 1;
+ }
+
+ return 0;
+}
+
+#if !defined (__OPTIMIZE__)
+Multicast_Manager::Host_Elem::Host_Elem (char *h_name, Multicast_Manager::Host_Elem *n)
+: host_name (h_name), checked_off (0), next (n)
+{
+}
+
+int
+Multicast_Manager::outstanding_hosts_remain (void)
+{
+ return Multicast_Manager::received_host_count > 0;
+}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/Multicast_Manager.h b/apps/drwho/Multicast_Manager.h
new file mode 100644
index 00000000000..e0b97de488a
--- /dev/null
+++ b/apps/drwho/Multicast_Manager.h
@@ -0,0 +1,55 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* This file handles all the operations upon host machines names
+ and addresses. */
+
+#ifndef _HOST_MANAGER_H
+#define _HOST_MANAGER_H
+
+#include "ace/OS.h"
+
+struct Host_Elem
+{
+ char *host_name;
+ in_addr host_addr;
+ int checked_off;
+ Host_Elem *next;
+
+ Host_Elem (char *h_name, Host_Elem *n);
+};
+
+class Multicast_Manager
+{
+public:
+ static void add_host (char *host_name);
+ static void checkoff_host (in_addr host_addr);
+ static int get_next_host_addr (in_addr &host_addr);
+ static int outstanding_hosts_remain (void);
+ static int get_next_non_responding_host (char *&host_name);
+ static int insert_hosts_from_file (char *filename);
+ static void insert_default_hosts (void);
+
+private:
+ static hostent *get_host_entry (char *host);
+
+ static int received_host_count;
+ static char *host_names[];
+ static Host_Elem *drwho_list;
+ static Host_Elem *current_ptr;
+};
+
+#ifdef __OPTIMIZE__
+inline
+Multicast_Manager::Host_Elem::Host_Elem (char *h_name, Multicast_Manager::Host_Elem *n)
+ : host_name (h_name), checked_off (0), next (n)
+{
+}
+
+inline int
+Multicast_Manager::outstanding_hosts_remain (void)
+{
+ return Multicast_Manager::received_host_count > 0;
+}
+#endif /* __OPTIMIZE__ */
+#endif /* _HOST_MANAGER_H */
diff --git a/apps/drwho/Options.cpp b/apps/drwho/Options.cpp
new file mode 100644
index 00000000000..bb102b3f6b1
--- /dev/null
+++ b/apps/drwho/Options.cpp
@@ -0,0 +1,152 @@
+// $Id$
+#include "global.h"
+#include "new.h"
+#include "Multicast_Manager.h"
+#include "ace/Get_Opt.h"
+#include "Options.h"
+
+/* Initialize all the static variables. */
+
+/* Contains bit-mask for options. */
+unsigned int Options::option_word = 0;
+
+/* Which protocol are we using? */
+Options::Protocol_Types Options::protocol_type = Options::PROTO_FLO;
+
+/* User name for quick lookups. */
+char *Options::user_name = 0;
+
+/* Port number for client/server. */
+short Options::port_number = PORT_NUMBER;
+
+/* Maximum time the client waits for servers to timeout. */
+int Options::max_server_timeout = 5;
+
+/* Name of the program. */
+char *Options::program_name;
+
+/* Default name of file that stores friend info. */
+char *Options::friend_file = FRIEND_FILE;
+
+void
+Options::print_usage_and_die (int long_msg)
+{
+ fprintf (stderr, "usage: %s %s", program_name,
+ long_msg
+ ? "\n"
+ "-?\tprints a short usage message\n"
+ "-A\tappend the following hostname to the list of predefined hostnames.\n"
+ "-a\treturn information on *all* users remotely logged in (uses yp passwd).\n"
+ "-b\trun the server in the background (i.e., as a daemon).\n"
+ "-d\tturn on debugging.\n"
+ "-F\tuse the following file contents to initialize the host list.\n"
+ "-f\tuse the following file contents to initialize the friends database.\n"
+ "-H\tuse the following hostname as part of the new list of hostnames.\n"
+ "\t(this option overwrites the existing default names).\n"
+ "-h\tprint a long usage message.\n"
+ "-L\tprint the login name rather than the real name (which is the default).\n"
+ "-l\tprint information in long format (works for all protocols).\n"
+ "-p\tset the port number (server must correspond).\n"
+ "-r\tdo the remote lookups (i.e., local operations are the default).\n"
+ "-R\tprint info using the rusers format.\n"
+ "-s\tsort the output by login name.\n"
+ "-S\tsort the output by real name.\n"
+ "-t\tset the amount of time we wait for servers to timeout.\n"
+ "-w\treturn information on just one user.\n"
+ : "[-?haAbdfFHhLlpRrtw]\n");
+ exit (1);
+}
+
+#ifndef __OPTIMIZE__
+void
+Options::set_opt (Option_Types opt)
+{
+ Options::option_word |= opt;
+}
+
+int
+Options::get_opt (Option_Types opt)
+{
+ return (Options::option_word & opt) != 0;
+}
+#endif /* __OPTIMIZE__ */
+
+void
+Options::set_options (int argc, char *argv[])
+{
+ int c;
+ int add_default_hosts = 1;
+
+ Options::program_name = argv[0];
+ Get_Opt getopt (argc, argv, "?aA:bdF:f:hH:Llp:rRsSt:w:");
+
+ while ((c = getopt ()) != -1)
+ {
+ switch (c)
+ {
+ case '?':
+ Options::print_usage_and_die (0);
+ /* NOTREACHED */
+ case 'A':
+ Multicast_Manager::add_host (getopt.optarg);
+ break;
+ case 'a':
+ Options::protocol_type = PROTO_ALL;
+ break;
+ case 'b':
+ Options::set_opt (Options::BE_A_DAEMON);
+ break;
+ case 'd':
+ Options::set_opt (Options::DEBUG);
+ break;
+ case 'f':
+ Options::friend_file = getopt.optarg;
+ break;
+ case 'F':
+ if (Multicast_Manager::insert_hosts_from_file (getopt.optarg) < 0)
+ perror (Options::program_name), exit (1);
+ add_default_hosts = 0;
+ break;
+ case 'H':
+ Multicast_Manager::add_host (getopt.optarg);
+ add_default_hosts = 0;
+ break;
+ case 'h':
+ Options::print_usage_and_die (1);
+ /* NOTREACHED */
+ case 'L':
+ Options::set_opt (Options::PRINT_LOGIN_NAME);
+ break;
+ case 'l':
+ Options::set_opt (Options::USE_VERBOSE_FORMAT);
+ break;
+ case 'p':
+ Options::port_number = atoi (getopt.optarg);
+ break;
+ case 'R':
+ Options::protocol_type = PROTO_RUSER;
+ break;
+ case 'r':
+ Options::set_opt (Options::REMOTE_USAGE);
+ break;
+ case 's':
+ Options::set_opt (Options::SORT_BY_LOGIN_NAME);
+ break;
+ case 'S':
+ Options::set_opt (Options::SORT_BY_REAL_NAME);
+ break;
+ case 't':
+ Options::max_server_timeout = atoi (getopt.optarg);
+ break;
+ case 'w':
+ Options::user_name = getopt.optarg;
+ Options::protocol_type = PROTO_USR;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (Options::get_opt (Options::REMOTE_USAGE) && add_default_hosts)
+ Multicast_Manager::insert_default_hosts ();
+}
diff --git a/apps/drwho/Options.h b/apps/drwho/Options.h
new file mode 100644
index 00000000000..1d9153cc974
--- /dev/null
+++ b/apps/drwho/Options.h
@@ -0,0 +1,71 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* This file is used to provide a consolidated Options.handling facility. */
+
+#ifndef _OPTIONS_H
+#define _OPTIONS_H
+
+/* Silly macros for handling message types. */
+#define GET_PACKET_TYPE(P) (ntohs (*((short *) P)))
+#define SET_PACKET_TYPE(P,T) ((*(short *) P) = ntohs (T))
+#define SKIP_PACKET_TYPE(P) ((P) + sizeof (short))
+#define SUBTRACT_PACKET_TYPE(L) ((L) - sizeof (short))
+
+class Options
+{
+ static void print_usage_and_die (int long_msg);
+ static unsigned int option_word;
+
+public:
+ enum Option_Types
+ {
+ REMOTE_USAGE = 01,
+ PRINT_LOGIN_NAME = 02,
+ DEBUG = 04,
+ STAND_ALONE_SERVER = 010,
+ SORT_BY_LOGIN_NAME = 020,
+ SORT_BY_REAL_NAME = 040,
+ USE_VERBOSE_FORMAT = 0100,
+ BE_A_DAEMON = 0200
+ };
+
+ /* Different types of messages. */
+ enum Protocol_Types
+ {
+ PROTO_USR = 1, /* Only return info on one user. */
+ PROTO_ALL = 2, /* Return info on all users logged in around the system. */
+ PROTO_FLO = 3, /* Return info on friends logged in. */
+ PROTO_RUSER = 4, /* Return info in ruser format! */
+
+ PROTO_RWHO = 5, /* Return info in rwho format. */
+ PROTO_WHO = 6, /* Return info in who format. */
+ PROTO_RUPTIME = 7 /* Return info in ruptime format. */
+ };
+
+ static void set_options (int argc, char *argv[]);
+ static void set_opt (Option_Types opt);
+ static int get_opt (Option_Types opt);
+
+ static short port_number;
+ static Protocol_Types protocol_type;
+ static int max_server_timeout;
+ static char *program_name;
+ static char *friend_file;
+ static char *user_name;
+};
+
+#ifdef __OPTIMIZE__
+inline void
+Options::set_opt (Option_Types opt)
+{
+ Options::option_word |= opt;
+}
+
+inline int
+Options::get_opt (Option_Types opt)
+{
+ return Options::option_word & opt;
+}
+#endif /* __OPTIMIZE__ */
+#endif /* _OPTIONS_H */
diff --git a/apps/drwho/PMC_All.cpp b/apps/drwho/PMC_All.cpp
new file mode 100644
index 00000000000..9758c6c0625
--- /dev/null
+++ b/apps/drwho/PMC_All.cpp
@@ -0,0 +1,85 @@
+// $Id$
+#include "global.h"
+#include "new.h"
+#include "Options.h"
+#include "HT_Client.h"
+#include "PMC_All.h"
+
+/* This function is pretty much a no-op that just sets up the appropriate
+ lookup function to use. */
+
+int
+PMC_All::encode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "in PMC_All::encode\n");
+
+ this->ss = new (PRIVATE_POOL) HT_Client;
+
+ SET_PACKET_TYPE (packet, Options::PROTO_ALL);
+
+ char *buf_ptr = SKIP_PACKET_TYPE (packet);
+
+ packet_length = buf_ptr - packet;
+ return 1;
+}
+
+/* This method is responsible for transforming the msg from the server
+ back into a form usable by the client. Note that it reads the REAL_NAME
+ from the packet (since the server placed it there)... */
+
+int
+PMC_All::decode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ {
+ fprintf (stderr, "in PMC_All::decode, packet_length = %d\n", packet_length);
+ write (2, packet, packet_length);
+ putc ('\n', stderr);
+ }
+ char *cp = packet;
+ int remote_users = 0;
+
+ sscanf (cp, "Users %d", &remote_users);
+
+ this->increment_total_users (remote_users);
+
+ for (cp = ACE::strend (cp); *cp != '\n'; cp++)
+ {
+ /* Skip over the LOGIN_NAME. */
+
+ char *login_name = cp;
+ char *real_name = cp = ACE::strend (cp);
+
+ for (cp = ACE::strend (cp);
+ *(cp = this->handle_protocol_entries (cp, login_name, real_name)) != '\t'
+ ;)
+ ;
+ }
+
+ return 1;
+}
+
+Protocol_Record *
+PMC_All::insert_protocol_info (Protocol_Record &protocol_record)
+{
+ Protocol_Record *frp = PM_Client::insert_protocol_info (protocol_record);
+ int length = strlen (frp->set_real (ACE::strnew (protocol_record.get_real ())));
+
+ if (length > this->max_key_length)
+ this->max_key_length = length;
+
+ return frp;
+}
+
+void
+PMC_All::process (void)
+{
+ printf ("remote users logged on\n");
+ PM_Client::process ();
+}
+
+#ifndef __OPTIMIZE__
+PMC_All::PMC_All (void)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/PMC_All.h b/apps/drwho/PMC_All.h
new file mode 100644
index 00000000000..0fd2a1e6192
--- /dev/null
+++ b/apps/drwho/PMC_All.h
@@ -0,0 +1,28 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the client's lookup table abstraction for `all' users... */
+
+#ifndef _FMC_ALL_H
+#define _FMC_ALL_H
+
+#include "PM_Client.h"
+
+class PMC_All : public PM_Client
+{
+protected:
+ Protocol_Record *insert_protocol_info (Protocol_Record &protocol_record);
+ virtual int encode (char *packet, int &total_bytes);
+ virtual int decode (char *packet, int &total_bytes);
+
+public:
+ PMC_All (void);
+ virtual void process (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+PMC_All::PMC_All (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif /* _FMC_ALL_H */
diff --git a/apps/drwho/PMC_Flo.cpp b/apps/drwho/PMC_Flo.cpp
new file mode 100644
index 00000000000..13dd5206934
--- /dev/null
+++ b/apps/drwho/PMC_Flo.cpp
@@ -0,0 +1,99 @@
+// $Id$
+#include "Options.h"
+#include "new.h"
+#include "BS_Client.h"
+#include "PMC_Flo.h"
+
+/* This function "encodes" a list of friends by putting the userid's in
+ a contiguous block. This block can then be transmitted over to the
+ network to servers on other subnets. Several things are added to
+ make decoding easier on the other end:
+
+ * A count of the number of friends is prepended (assumption: there
+ are no more than 9999999 friends... ;-))
+ * The login userids are separated by a single space. */
+
+int
+PMC_Flo::encode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "in PMC_Flo::encode");
+
+ this->ss = new (PRIVATE_POOL) BS_Client;
+
+ SET_PACKET_TYPE (packet, Options::PROTO_FLO);
+ char *buf_ptr = SKIP_PACKET_TYPE (packet);
+
+ sprintf (buf_ptr, "%d", this->friend_count ());
+
+ buf_ptr += MAXUSERIDNAMELEN;
+
+ /* Loop through all the friends, copying them into the packet buffer. */
+
+ for (Protocol_Record *frp; (frp = this->get_next_friend ()) != 0; )
+ buf_ptr = ACE::strecpy (buf_ptr, frp->get_login ());
+
+ packet_length = buf_ptr - packet;
+
+ if (Options::get_opt (Options::DEBUG) != 0)
+ {
+ fprintf (stderr, ", packet_length = %d\n", packet_length);
+ write (2, packet, packet_length);
+ putc ('\n', stderr);
+ }
+ return 1;
+}
+
+/* This method is responsible for transforming the msg from the server
+ back into a form usable by the client. */
+
+int
+PMC_Flo::decode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ {
+ fprintf (stderr, "in PMC_Flo::decode, packet_length = %d\n", packet_length);
+ write (2, packet, packet_length);
+ putc ('\n', stderr);
+ }
+ char *cp = packet;
+ int remote_users = 0;
+
+ sscanf (cp, "Users %d", &remote_users);
+
+ this->increment_total_users (remote_users);
+
+ for (cp = ACE::strend (cp); *cp != '\n'; cp++)
+ {
+ char *login_name = cp;
+
+ for (cp = ACE::strend (cp); *(cp = this->handle_protocol_entries (cp, login_name)) != '\t'; )
+ ;
+ }
+
+ return 1;
+}
+
+Protocol_Record *
+PMC_Flo::insert_protocol_info (Protocol_Record &protocol_record)
+{
+ Protocol_Record *frp = PM_Client::insert_protocol_info (protocol_record);
+ int length = strlen (frp->get_real ());
+
+ if (length > this->max_key_length)
+ this->max_key_length = length;
+
+ return frp;
+}
+
+void
+PMC_Flo::process (void)
+{
+ printf ("remote friends logged on\n");
+ PM_Client::process ();
+}
+
+#ifndef __OPTIMIZE__
+PMC_Flo::PMC_Flo (void)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/PMC_Flo.h b/apps/drwho/PMC_Flo.h
new file mode 100644
index 00000000000..06ef2295495
--- /dev/null
+++ b/apps/drwho/PMC_Flo.h
@@ -0,0 +1,28 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the client's lookup table abstraction for `flo' users... */
+
+#ifndef _FMC_FLO_H
+#define _FMC_FLO_H
+
+#include "PM_Client.h"
+
+class PMC_Flo : public PM_Client
+{
+protected:
+ virtual Protocol_Record *insert_protocol_info (Protocol_Record &protocol_record);
+ virtual int encode (char *packet, int &total_bytes);
+ virtual int decode (char *packet, int &total_bytes);
+
+public:
+ PMC_Flo (void);
+ virtual void process (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+PMC_Flo::PMC_Flo (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif /* _FMC_FLO_H */
diff --git a/apps/drwho/PMC_Ruser.cpp b/apps/drwho/PMC_Ruser.cpp
new file mode 100644
index 00000000000..de71941f940
--- /dev/null
+++ b/apps/drwho/PMC_Ruser.cpp
@@ -0,0 +1,137 @@
+// $Id$
+#include "global.h"
+#include "new.h"
+#include "Options.h"
+#include "HT_Client.h"
+#include "PMC_Ruser.h"
+
+/* This function is pretty much a no-op that just sets up the appropriate
+ lookup function to use. */
+
+int
+PMC_Ruser::encode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "in PMC_Ruser::encode\n");
+
+ this->ss = new (PRIVATE_POOL) HT_Client;
+
+ SET_PACKET_TYPE (packet, Options::PROTO_RUSER);
+
+ char *buf_ptr = SKIP_PACKET_TYPE (packet);
+
+ *buf_ptr++ = char (Options::get_opt (Options::PRINT_LOGIN_NAME));
+
+ packet_length = buf_ptr - packet;
+ return 1;
+}
+
+/* This method is responsible for transforming the msg from the server
+ back into a form usable by the client. Note that it reads the REAL_NAME
+ from the packet (since the server placed it there)... */
+
+int
+PMC_Ruser::decode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ {
+ fprintf (stderr, "in PMC_Ruser::decode, packet_length = %d\n", packet_length);
+ write (2, packet, packet_length);
+ putc ('\n', stderr);
+ }
+ char *cp = packet;
+ int remote_users = 0;
+
+ sscanf (cp, "Users %d", &remote_users);
+
+ this->increment_total_users (remote_users);
+
+ for (cp = ACE::strend (cp); *cp != '\n'; cp++)
+ {
+ char *host_name = cp;
+
+ for (cp = ACE::strend (cp); *(cp = this->handle_protocol_entries (cp, host_name)) != '\t'; )
+ ;
+ }
+
+ return 1;
+}
+
+Protocol_Record *
+PMC_Ruser::insert_protocol_info (Protocol_Record &protocol_record)
+{
+ Protocol_Record *frp = this->ss->insert (protocol_record.get_host (), MAXHOSTNAMELEN);
+ Drwho_Node *current_node = protocol_record.get_drwho_list ();
+ Drwho_Node *np = this->get_drwho_node (ACE::strnnew (current_node->get_login_name (), MAXUSERIDNAMELEN), frp->drwho_list);
+ int length = strlen (frp->get_host ());
+
+ np->set_real_name (ACE::strnew (current_node->get_real_name ()));
+
+ if (np->get_active_count () < current_node->get_active_count ())
+ np->set_active_count (current_node->get_active_count ());
+ if (np->get_inactive_count () < current_node->get_inactive_count())
+ np->set_inactive_count (current_node->get_inactive_count ());
+
+ if (length > this->max_key_length)
+ this->max_key_length = length;
+
+ return frp;
+}
+
+char *
+PMC_Ruser::handle_protocol_entries (char *cp, char *host_name, char *)
+{
+ static Protocol_Record protocol_record (1);
+ auto Drwho_Node *current_node = protocol_record.get_drwho_list ();
+
+ protocol_record.set_host (host_name);
+ current_node->set_inactive_count (atoi (cp));
+ current_node->set_active_count (atoi (cp = strchr (cp, ' ') + 1));
+ current_node->set_login_name (cp = strchr (cp, ' ') + 1);
+ current_node->set_real_name (cp = strchr (cp, '\0') + 1);
+
+ this->insert_protocol_info (protocol_record);
+
+ return ACE::strend (cp);
+}
+
+void
+PMC_Ruser::process (void)
+{
+ auto char *(Drwho_Node::*get_name)(void) =
+ Options::get_opt (Options::PRINT_LOGIN_NAME) ? &Drwho_Node::get_login_name : &Drwho_Node::get_real_name;
+
+ for (Protocol_Record *frp; (frp = this->Protocol_Manager::get_each_friend ()) != 0; )
+ {
+ printf ("%-*s ", this->max_key_length, frp->get_host ());
+
+ for (Drwho_Node *np = frp->get_drwho_list (); ;)
+ {
+ fputs ((np->*get_name) (), stdout);
+
+ if (np->get_inactive_count () != 0)
+ {
+ if (np->get_active_count () != 0)
+ printf ("*(%d)", np->get_active_count ());
+ }
+ else if (np->get_active_count () > 1)
+ printf ("*(%d)", np->get_active_count ());
+ else if (np->get_active_count () == 1)
+ putchar ('*');
+
+ if ((np = np->next) == 0)
+ break;
+ else if (Options::get_opt (Options::PRINT_LOGIN_NAME))
+ putchar (' ');
+ else
+ printf (", ");
+ }
+
+ putchar ('\n');
+ }
+}
+
+#ifndef __OPTIMIZE__
+PMC_Ruser::PMC_Ruser (void)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/PMC_Ruser.h b/apps/drwho/PMC_Ruser.h
new file mode 100644
index 00000000000..936f29854d0
--- /dev/null
+++ b/apps/drwho/PMC_Ruser.h
@@ -0,0 +1,29 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the client's lookup table abstraction for `ruser' users... */
+
+#ifndef _FMC_RUSER_H
+#define _FMC_RUSER_H
+
+#include "PM_Client.h"
+
+class PMC_Ruser : public PM_Client
+{
+protected:
+ char *handle_protocol_entries (char *cp, char *host_name, char * = 0);
+ Protocol_Record *insert_protocol_info (Protocol_Record &protocol_record);
+ virtual int encode (char *packet, int &total_bytes);
+ virtual int decode (char *packet, int &total_bytes);
+
+public:
+ PMC_Ruser (void);
+ virtual void process (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+PMC_Ruser::PMC_Ruser (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif /* _FMC_RUSER_H */
diff --git a/apps/drwho/PMC_Usr.cpp b/apps/drwho/PMC_Usr.cpp
new file mode 100644
index 00000000000..f6a1a7d2d33
--- /dev/null
+++ b/apps/drwho/PMC_Usr.cpp
@@ -0,0 +1,93 @@
+// $Id$
+#include "Options.h"
+#include "new.h"
+#include "SL_Client.h"
+#include "PMC_Usr.h"
+
+int
+PMC_Usr::encode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "in PMC_Usr::encode");
+
+ this->ss = new (PRIVATE_POOL) SL_Client (this->usr_name);
+
+ SET_PACKET_TYPE (packet, Options::PROTO_USR);
+
+ char *buf_ptr = SKIP_PACKET_TYPE (packet);
+
+ buf_ptr = ACE::strecpy (buf_ptr, this->get_next_friend ()->get_login ());
+
+ packet_length = buf_ptr - packet;
+
+ if (Options::get_opt (Options::DEBUG) != 0)
+ {
+ fprintf (stderr, ", packet_length = %d\n", packet_length);
+ write (2, packet, packet_length);
+ putc ('\n', stderr);
+ }
+ return 1;
+}
+
+/* This method is responsible for transforming the msg from the server
+ back into a form usable by the client. */
+
+int
+PMC_Usr::decode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ {
+ fprintf (stderr, "in PMC_Usr::decode, packet_length = %d\n", packet_length);
+ write (2, packet, packet_length);
+ putc ('\n', stderr);
+ }
+
+ char *cp = packet;
+
+ if (*cp != '\n')
+ {
+ char *login_name = cp;
+
+ for (cp = ACE::strend (cp); *(cp = this->handle_protocol_entries (cp, login_name)) != '\t'; )
+ ;
+ }
+ return 1;
+}
+
+void
+PMC_Usr::process (void)
+{
+ Protocol_Record *frp = this->get_each_friend ();
+ Drwho_Node *np = frp->get_drwho_list ();
+
+ if (np == 0)
+ fputs ("<unknown>", stdout);
+ else
+ {
+
+ /* First try to get a login session that is active... */
+
+ for (; np != 0; np = np->next)
+ if (np->active_count > 0)
+ {
+ printf ("%s ", np->get_host_name ());
+
+ if (Options::get_opt (Options::USE_VERBOSE_FORMAT) == 0)
+ return;
+ }
+
+ for (np = frp->get_drwho_list (); np != 0; np = np->next)
+ if (np->active_count == 0)
+ {
+ printf ("%s ", np->get_host_name ());
+
+ if (Options::get_opt (Options::USE_VERBOSE_FORMAT) == 0)
+ return;
+ }
+ }
+}
+
+#ifndef __OPTIMIZE__
+PMC_Usr::PMC_Usr (char *u_name): usr_name (u_name)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/PMC_Usr.h b/apps/drwho/PMC_Usr.h
new file mode 100644
index 00000000000..03195f12586
--- /dev/null
+++ b/apps/drwho/PMC_Usr.h
@@ -0,0 +1,30 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the client's lookup table abstraction for `Usr' users... */
+
+#ifndef _FMC_USR_H
+#define _FMC_USR_H
+
+#include "PM_Client.h"
+
+class PMC_Usr : public PM_Client
+{
+private:
+ char *usr_name;
+
+protected:
+ virtual int encode (char *packet, int &total_bytes);
+ virtual int decode (char *packet, int &total_bytes);
+
+public:
+ PMC_Usr (char *usr_name);
+ virtual void process (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+PMC_Usr::PMC_Usr (char *u_name): usr_name (u_name)
+{}
+#endif /* __OPTIMIZE__ */
+#endif /* _FMC_USR_H */
diff --git a/apps/drwho/PMS_All.cpp b/apps/drwho/PMS_All.cpp
new file mode 100644
index 00000000000..d28f21f9bcc
--- /dev/null
+++ b/apps/drwho/PMS_All.cpp
@@ -0,0 +1,76 @@
+// $Id$
+#include "Options.h"
+#include "new.h"
+#include "HT_Server.h"
+#include "PMS_All.h"
+
+/* This function packs the located friends userids, plus the machines
+ they are logged into (along with the inactive and active counts on
+ each machine) into a buffer that is subsequently transmitted back
+ to the client across the network. Note that this function encodes
+ the REAL_NAME of the user in the packet. */
+
+int
+PMS_All::encode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "in PMS_All::encode");
+
+ Protocol_Record *frp;
+ char *buf_ptr = packet;
+
+ sprintf (buf_ptr, "Users %d", this->get_total_users ());
+ buf_ptr += strlen (buf_ptr) + 1;
+
+ /* We only send back info on friends that we actually see logged in. */
+
+ for (; (frp = this->get_next_friend ()) != 0; *buf_ptr++ = '\t')
+ buf_ptr = this->handle_protocol_entries (ACE::strecpy (ACE::strecpy (buf_ptr, frp->get_login ()), frp->get_real ()), frp->get_drwho_list ());
+
+ *buf_ptr++ = '\n';
+ packet_length = buf_ptr - packet;
+
+ if (Options::get_opt (Options::DEBUG) != 0)
+ {
+ fprintf (stderr, ", packet_length = %d\n", packet_length);
+ write (2, packet, packet_length);
+ putc ('\n', stderr);
+ }
+ return 1;
+}
+
+/* This function takes a packet received from the client and calls
+ the appropriate Protocol_Manager routine to build the local table of
+ friends. */
+
+int
+PMS_All::decode (char *, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "in PMS_All::decode, packet_length = %d\n", packet_length);
+
+ this->ss = new (PRIVATE_POOL) HT_Server;
+ return 1;
+}
+
+/* We only want the user's real name, not the gecos junk after the first leading ','.
+ However, if the real-name is not in the password file, just return the login name
+ instead. */
+
+Protocol_Record *
+PMS_All::insert_protocol_info (Protocol_Record &protocol_record)
+{
+ Protocol_Record *frp = PM_Server::insert_protocol_info (protocol_record);
+ passwd *pwent = getpwnam (frp->get_login ());
+ char *cp;
+
+ if ((cp = strchr (frp->set_real (pwent == 0 ? frp->get_login () : ACE::strnew (pwent->pw_gecos)), ',')) != 0)
+ *cp = '\0';
+
+ return frp;
+}
+
+#ifndef __OPTIMIZE__
+PMS_All::PMS_All (void)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/PMS_All.h b/apps/drwho/PMS_All.h
new file mode 100644
index 00000000000..559e7674eea
--- /dev/null
+++ b/apps/drwho/PMS_All.h
@@ -0,0 +1,27 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the server's lookup table abstraction for `all' users... */
+
+#ifndef _FMS_ALL_H
+#define _FMS_ALL_H
+
+#include "PM_Server.h"
+
+class PMS_All : public PM_Server
+{
+protected:
+ virtual Protocol_Record *insert_protocol_info (Protocol_Record &protocol_record);
+ virtual int encode (char *packet, int &total_bytes);
+ virtual int decode (char *packet, int &total_bytes);
+
+public:
+ PMS_All (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+PMS_All::PMS_All (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif /* _FMS_ALL_H */
diff --git a/apps/drwho/PMS_Flo.cpp b/apps/drwho/PMS_Flo.cpp
new file mode 100644
index 00000000000..692d316b7cf
--- /dev/null
+++ b/apps/drwho/PMS_Flo.cpp
@@ -0,0 +1,58 @@
+// $Id$
+#include "Options.h"
+#include "new.h"
+#include "BS_Server.h"
+#include "PMS_Flo.h"
+
+/* This function packs the located friends userids, plus the machines
+ they are logged into (along with the inactive and active counts on
+ each machine) into a buffer that is subsequently transmitted back
+ to the client across the network. */
+
+int
+PMS_Flo::encode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "in PMS_Flo::encode");
+
+ Protocol_Record *frp;
+ char *buf_ptr = packet;
+
+ sprintf (buf_ptr, "Users %d", this->get_total_users ());
+ buf_ptr += strlen (buf_ptr) + 1;
+
+ /* We only send back info on friends that we actually see logged in. */
+
+ for (; (frp = this->get_next_friend ()) != 0; *buf_ptr++ = '\t')
+ buf_ptr = this->handle_protocol_entries (ACE::strecpy (buf_ptr, frp->get_login ()), frp->get_drwho_list ());
+
+ *buf_ptr++ = '\n';
+ packet_length = buf_ptr - packet;
+
+ if (Options::get_opt (Options::DEBUG) != 0)
+ {
+ fprintf (stderr, ", packet_length = %d\n", packet_length);
+ write (2, packet, packet_length);
+ putc ('\n', stderr);
+ }
+ return 1;
+}
+
+/* This function takes a packet received from the client and calls
+ the appropriate Protocol_Manager routine to build the local table of
+ friends. */
+
+int
+PMS_Flo::decode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "in PMS_Flo::decode, packet_length = %d\n", packet_length);
+
+ this->ss = new (PRIVATE_POOL) BS_Server (packet);
+ return 1;
+}
+
+#ifndef __OPTIMIZE__
+PMS_Flo::PMS_Flo (void)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/PMS_Flo.h b/apps/drwho/PMS_Flo.h
new file mode 100644
index 00000000000..e095b5f4ec6
--- /dev/null
+++ b/apps/drwho/PMS_Flo.h
@@ -0,0 +1,26 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the server's lookup table abstraction for `flo' users... */
+
+#ifndef _FMS_FLO_H
+#define _FMS_FLO_H
+
+#include "PM_Server.h"
+
+class PMS_Flo : public PM_Server
+{
+protected:
+ virtual int encode (char *packet, int &total_bytes);
+ virtual int decode (char *packet, int &total_bytes);
+
+public:
+ PMS_Flo (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+PMS_Flo::PMS_Flo (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif
diff --git a/apps/drwho/PMS_Ruser.cpp b/apps/drwho/PMS_Ruser.cpp
new file mode 100644
index 00000000000..ca49e998a3c
--- /dev/null
+++ b/apps/drwho/PMS_Ruser.cpp
@@ -0,0 +1,103 @@
+// $Id$
+#include "Options.h"
+#include "new.h"
+#include "HT_Server.h"
+#include "PMS_Ruser.h"
+
+/* This function packs the located friends userids, plus the machines
+ they are logged into (along with the inactive and active counts on
+ each machine) into a buffer that is subsequently transmitted back
+ to the client across the network. Note that this function encodes
+ the REAL_NAME of the user in the packet. */
+
+int
+PMS_Ruser::encode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "in PMS_Ruser::encode");
+
+ Protocol_Record *frp;
+ char *buf_ptr = packet;
+
+ sprintf (buf_ptr, "Users %d", this->get_total_users ());
+ buf_ptr += strlen (buf_ptr) + 1;
+
+ /* We only send back info on hosts that we actually see. */
+
+ for (; (frp = this->get_next_friend ()) != 0; *buf_ptr++ = '\t')
+ buf_ptr = this->handle_protocol_entries (ACE::strecpy (buf_ptr, frp->get_host ()), frp->get_drwho_list ());
+
+ *buf_ptr++ = '\n';
+ packet_length = buf_ptr - packet;
+
+ if (Options::get_opt (Options::DEBUG) != 0)
+ {
+ fprintf (stderr, ", packet_length = %d\n", packet_length);
+ write (2, packet, packet_length);
+ putc ('\n', stderr);
+ }
+ return 1;
+}
+
+/* This function takes a packet received from the client and crusers
+ the appropriate Protocol_Manager routine to build the local table of
+ friends. */
+
+int
+PMS_Ruser::decode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "in PMS_Ruser::decode, packet_length = %d\n", packet_length);
+
+ if (*packet)
+ Options::set_opt (Options::PRINT_LOGIN_NAME);
+
+ this->ss = new (PRIVATE_POOL) HT_Server;
+ return 1;
+}
+
+Protocol_Record *
+PMS_Ruser::insert_protocol_info (Protocol_Record &protocol_record)
+{
+ Drwho_Node *current_node = protocol_record.get_drwho_list ();
+ Protocol_Record *frp = this->ss->insert (current_node->get_host_name (), MAXHOSTNAMELEN);
+ Drwho_Node *np = this->get_drwho_node (ACE::strnnew (protocol_record.get_login (), MAXUSERIDNAMELEN), frp->drwho_list);
+
+ if (Options::get_opt (Options::PRINT_LOGIN_NAME))
+ np->set_real_name ("");
+ else
+ {
+ passwd *pwent = getpwnam (np->get_login_name ());
+ char *cp;
+
+ if ((cp = strchr (np->set_real_name (pwent == 0 ? np->get_login_name () : ACE::strnew (pwent->pw_gecos)), ',')) != 0)
+ *cp = '\0';
+ }
+
+ if (current_node->get_idle_time () >= MAX_USER_TIMEOUT)
+ np->inactive_count++;
+ else
+ np->active_count++;
+
+ return frp;
+}
+
+char *
+PMS_Ruser::handle_protocol_entries (char *buf_ptr, Drwho_Node *np)
+{
+
+ for (; np != 0; np = np->next)
+ {
+ sprintf (buf_ptr, "%d %d ", np->get_inactive_count (), np->get_active_count ());
+ buf_ptr += strlen (buf_ptr);
+
+ buf_ptr = ACE::strecpy (ACE::strecpy (buf_ptr, np->get_login_name ()), np->get_real_name ());
+ }
+
+ return buf_ptr;
+}
+
+#ifndef __OPTIMIZE__
+PMS_Ruser::PMS_Ruser (void)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/PMS_Ruser.h b/apps/drwho/PMS_Ruser.h
new file mode 100644
index 00000000000..0111580c3f9
--- /dev/null
+++ b/apps/drwho/PMS_Ruser.h
@@ -0,0 +1,28 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the server's lookup table abstraction for `ruser' users... */
+
+#ifndef _FMS_RUSER_H
+#define _FMS_RUSER_H
+
+#include "PM_Server.h"
+
+class PMS_Ruser : public PM_Server
+{
+protected:
+ virtual char *handle_protocol_entries (char *bp, Drwho_Node *hp);
+ virtual Protocol_Record *insert_protocol_info (Protocol_Record &protocol_record);
+ virtual int encode (char *packet, int &total_bytes);
+ virtual int decode (char *packet, int &total_bytes);
+
+public:
+ PMS_Ruser (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+PMS_Ruser::PMS_Ruser (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif /* _FMS_RUSER_H */
diff --git a/apps/drwho/PMS_Usr.cpp b/apps/drwho/PMS_Usr.cpp
new file mode 100644
index 00000000000..900bec14dfa
--- /dev/null
+++ b/apps/drwho/PMS_Usr.cpp
@@ -0,0 +1,66 @@
+// $Id$
+#include "Options.h"
+#include "new.h"
+#include "SL_Server.h"
+#include "PMS_Usr.h"
+
+/* This function "encodes" a list of friends by putting the userid's in
+ a contiguous block. This block can then be transmitted over to the
+ network to servers on other subnets. Several things are added to
+ make decoding easier on the other end:
+
+ * A count of the number of friends is prepended (assumption: there
+ are no more than 9999999 friends... ;-))
+ * The login userids are separated by a single space. */
+
+int
+PMS_Usr::encode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ fprintf (stderr, "in PMS_Usr::encode");
+
+ char *buf_ptr = packet;
+
+ /* We only send back info on friend that is actually logged in. */
+
+ Protocol_Record *frp = this->get_next_friend ();
+
+ if (frp)
+ {
+ buf_ptr = this->handle_protocol_entries (ACE::strecpy (buf_ptr, frp->get_login ()), frp->get_drwho_list ());
+ *buf_ptr++ = '\t';
+ }
+
+ *buf_ptr++ = '\n';
+ packet_length = buf_ptr - packet;
+
+ if (Options::get_opt (Options::DEBUG) != 0)
+ {
+ fprintf (stderr, ", packet_length = %d\n", packet_length);
+ write (2, packet, packet_length);
+ putc ('\n', stderr);
+ }
+ return 1;
+}
+
+/* This function takes a packet received from the client and calls
+ the appropriate Protocol_Manager routine to build the local table of
+ friends. */
+
+int
+PMS_Usr::decode (char *packet, int &packet_length)
+{
+ if (Options::get_opt (Options::DEBUG) != 0)
+ {
+ fprintf (stderr, "in PMS_Usr::decode, packet_length = %d\n", packet_length);
+ write (2, packet, packet_length);
+ putc ('\n', stderr);
+ }
+ this->ss = new (PRIVATE_POOL) SL_Server (packet);
+ return 1;
+}
+
+#ifndef __OPTIMIZE__
+PMS_Usr::PMS_Usr (void)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/PMS_Usr.h b/apps/drwho/PMS_Usr.h
new file mode 100644
index 00000000000..d9cd7094da1
--- /dev/null
+++ b/apps/drwho/PMS_Usr.h
@@ -0,0 +1,26 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the client's lookup table abstraction for `Usr' users... */
+
+#ifndef _FMS_USR_H
+#define _FMS_USR_H
+
+#include "PM_Server.h"
+
+class PMS_Usr : public PM_Server
+{
+protected:
+ virtual int encode (char *packet, int &total_bytes);
+ virtual int decode (char *packet, int &total_bytes);
+
+public:
+ PMS_Usr (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+PMS_Usr::PMS_Usr (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif /* _FMS_USR_H */
diff --git a/apps/drwho/PM_Client.cpp b/apps/drwho/PM_Client.cpp
new file mode 100644
index 00000000000..ba37746484f
--- /dev/null
+++ b/apps/drwho/PM_Client.cpp
@@ -0,0 +1,106 @@
+// $Id$
+#include "Options.h"
+#include "PM_Server.h"
+#include "PM_Client.h"
+
+/* This function is used to merge the LOGIN_NAME from server HOST_NAME
+ into the userids kept on the client's side. Note that we must
+ allocate memory for HOST_NAME... */
+
+Protocol_Record *
+PM_Client::insert_protocol_info (Protocol_Record &protocol_record)
+{
+ Protocol_Record *frp = this->ss->insert (protocol_record.get_login ());
+ Drwho_Node *current_node = protocol_record.get_drwho_list ();
+ Drwho_Node *np = this->get_drwho_node (ACE::strnew (current_node->get_host_name ()), frp->drwho_list);
+
+ /* Update the active and inactive counts. */
+
+ if (np->get_active_count () < current_node->get_active_count ())
+ {
+ np->set_active_count (current_node->get_active_count ());
+ frp->is_active = 1;
+ }
+ if (np->get_inactive_count () < current_node->get_inactive_count())
+ np->set_inactive_count (current_node->get_inactive_count ());
+
+ return frp;
+}
+
+/* This routine does all the dirty work, and actually prints out the
+ friends info in a nicely formatted manner. */
+
+void
+PM_Client::process (void)
+{
+ char *(Protocol_Record::*get_name)(void) = Options::get_opt (Options::PRINT_LOGIN_NAME) ? &Protocol_Record::get_login : &Protocol_Record::get_real;
+
+ int active_friends = 0;
+ int users = this->Protocol_Manager::get_total_users ();
+
+ printf ("------------------------\n");
+
+ if (Options::get_opt (Options::PRINT_LOGIN_NAME))
+ this->max_key_length = MAXUSERIDNAMELEN;
+
+ /* Goes through the queue of all the logged in friends and prints
+ out the associated information. */
+
+ for (Protocol_Record *frp; (frp = this->Protocol_Manager::get_each_friend ()) != 0; )
+ {
+ printf ("%c%-*s [", (frp->is_active != 0 ? '*' : ' '),
+ this->max_key_length, (frp->*get_name) ());
+
+ for (Drwho_Node *np = frp->get_drwho_list (); ;)
+ {
+ fputs (np->get_host_name (), stdout);
+
+ active_friends += np->get_active_count ();
+
+ if (np->get_inactive_count () != 0)
+ {
+ if (np->get_active_count () != 0)
+ printf ("*(%d)", np->get_active_count ());
+ }
+ else if (np->get_active_count () > 1)
+ printf ("*(%d)", np->get_active_count ());
+ else if (np->get_active_count () == 1)
+ putchar ('*');
+
+ if ((np = np->next) == 0)
+ break;
+ else
+ putchar (' ');
+ }
+
+ printf ("]\n");
+ }
+
+ printf ("------------------------\n");
+ printf ("friends: %d\tusers: %d\n", active_friends, users);
+}
+
+char *
+PM_Client::handle_protocol_entries (char *cp, char *login_name, char *real_name)
+{
+ static Protocol_Record protocol_record (1);
+ Drwho_Node *current_node = protocol_record.get_drwho_list ();
+
+ protocol_record.set_login (login_name);
+ protocol_record.set_real (real_name);
+ current_node->set_inactive_count (atoi (cp));
+ current_node->set_active_count (atoi (cp = strchr (cp, ' ') + 1));
+ current_node->set_host_name (cp = strchr (cp, ' ') + 1);
+
+ this->insert_protocol_info (protocol_record);
+
+ return ACE::strend (cp);
+}
+
+#ifndef __OPTIMIZE__
+PM_Client::PM_Client (void): max_key_length (0)
+{}
+
+PM_Client::~PM_Client (void)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/PM_Client.h b/apps/drwho/PM_Client.h
new file mode 100644
index 00000000000..ff1c20f32fa
--- /dev/null
+++ b/apps/drwho/PM_Client.h
@@ -0,0 +1,37 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the client side of the friend manager lookup table abstraction. */
+
+#ifndef _PM_CLIENT_H
+#define _PM_CLIENT_H
+
+#include "Protocol_Manager.h"
+
+class PM_Client : public Protocol_Manager
+{
+protected:
+ int max_key_length;
+
+ virtual char *handle_protocol_entries (char *cp, char *key_name1, char *key_name2 = 0);
+ virtual Protocol_Record *insert_protocol_info (Protocol_Record &protocol_record);
+public:
+ PM_Client (void);
+ virtual ~PM_Client (void);
+
+ virtual int encode (char *packet, int &total_bytes) = 0;
+ virtual int decode (char *packet, int &total_bytes) = 0;
+ virtual void process (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+PM_Client::PM_Client (void): max_key_length (0)
+{}
+
+inline
+PM_Client::~PM_Client (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif /* _PM_CLIENT_H */
+
diff --git a/apps/drwho/PM_Server.cpp b/apps/drwho/PM_Server.cpp
new file mode 100644
index 00000000000..bd47013606b
--- /dev/null
+++ b/apps/drwho/PM_Server.cpp
@@ -0,0 +1,72 @@
+// $Id$
+#include "Options.h"
+#include "Rwho_DB_Manager.h"
+#include "PM_Server.h"
+
+/* This is the main method for the server side of things. It
+ reads the RWHO file on the local machine and inserts HOST_NAME
+ information for each LOGIN_NAME that is a friend into the DRWHO_LIST.
+ This function is also responsible for determining whether a given
+ LOGIN_NAME is currently idle or not. */
+
+int
+PM_Server::process (void)
+{
+ RWho_DB_Manager ru;
+ Protocol_Record protocol_record (1);
+
+ while (ru.get_next_user (protocol_record) > 0)
+ this->insert_protocol_info (protocol_record);
+
+ return 1;
+}
+
+/* Insert the HOST_NAME into the server's lookup table on behalf of
+ user LOGIN_NAME. Note that we need to allocate memory for
+ HOST_NAME... */
+
+Protocol_Record *
+PM_Server::insert_protocol_info (Protocol_Record &protocol_record)
+{
+ Protocol_Record *frp = this->ss->insert (protocol_record.get_login ());
+
+ Drwho_Node *current_node = protocol_record.get_drwho_list ();
+
+ if (current_node->get_idle_time () < MAX_USER_TIMEOUT)
+ this->increment_total_users ();
+
+ if (frp)
+ {
+ Drwho_Node *np = this->get_drwho_node (ACE::strnew (current_node->get_host_name ()), frp->drwho_list);
+
+ if (current_node->get_idle_time () >= MAX_USER_TIMEOUT)
+ np->inactive_count++;
+ else
+ np->active_count++;
+ }
+
+ return frp;
+}
+
+/* Put the inactive and active counts, plus the hostname into the packet. */
+
+char *
+PM_Server::handle_protocol_entries (char *buf_ptr, Drwho_Node *np)
+{
+
+ for (; np != 0; np = np->next)
+ {
+ sprintf (buf_ptr, "%d %d %s", np->get_inactive_count (), np->get_active_count (), np->get_host_name ());
+ buf_ptr += strlen (buf_ptr) + 1;
+ }
+
+ return buf_ptr;
+}
+
+#ifndef __OPTIMIZE__
+PM_Server::PM_Server (void)
+{}
+
+PM_Server::~PM_Server (void)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/PM_Server.h b/apps/drwho/PM_Server.h
new file mode 100644
index 00000000000..2b9b497aee4
--- /dev/null
+++ b/apps/drwho/PM_Server.h
@@ -0,0 +1,35 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Handle the server's lookup table abstraction. */
+
+#ifndef _PM_SERVER_H
+#define _PM_SERVER_H
+
+#include "Protocol_Manager.h"
+
+class PM_Server : public Protocol_Manager
+{
+protected:
+ virtual char *handle_protocol_entries (char *bp, Drwho_Node *hp);
+ virtual Protocol_Record *insert_protocol_info (Protocol_Record &protocol_record);
+
+public:
+ PM_Server (void);
+ virtual ~PM_Server (void);
+
+ virtual int encode (char *packet, int &total_bytes) = 0;
+ virtual int decode (char *packet, int &total_bytes) = 0;
+ virtual int process (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+PM_Server::PM_Server (void)
+{}
+
+inline
+PM_Server::~PM_Server (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif
diff --git a/apps/drwho/Protocol_Manager.cpp b/apps/drwho/Protocol_Manager.cpp
new file mode 100644
index 00000000000..a31f4041d10
--- /dev/null
+++ b/apps/drwho/Protocol_Manager.cpp
@@ -0,0 +1,83 @@
+// $Id$
+#include "Options.h"
+#include "new.h"
+#include "Protocol_Manager.h"
+
+#if 0
+/* Static initializers. */
+int Protocol_Manager::total_users = 0;
+Search_Struct *Protocol_Manager::ss = 0;
+#endif
+
+/* Functions shared between client and server. */
+
+/* Returns a pointer to the Drwho_Node associated with HOST_NAME (if
+ it exists, otherwise a new node is created. Note that if a
+ Drwho_Node is found it is moved to the front of the list so that
+ subsequent finds are faster (i.e., self-organizing!) */
+
+Drwho_Node *
+Protocol_Manager::get_drwho_node (char *key_name, Drwho_Node *&head)
+{
+ for (Drwho_Node **temp = &head; *temp != 0; temp = &(*temp)->next)
+ if (strcmp (key_name, (*temp)->get_login_name ()) == 0)
+ break;
+
+ if (*temp == 0)
+ return head = new (PRIVATE_POOL) Drwho_Node (key_name, head);
+ else
+ {
+ Drwho_Node *t = *temp;
+
+ *temp = (*temp)->next;
+ t->next = head;
+ return head = t;
+ }
+}
+
+#ifndef __OPTIMIZE__
+Protocol_Manager::Protocol_Manager (void): total_users (0)
+{}
+
+Protocol_Manager::~Protocol_Manager (void)
+{
+ if (Options::get_opt (Options::DEBUG))
+ fprintf (stderr, "disposing Protocol_Manager\n");
+}
+
+/* Returns the next friend in the sequence of sorted friends. */
+
+Protocol_Record *
+Protocol_Manager::get_next_friend (void)
+{
+ return this->ss->get_next_entry ();
+}
+
+Protocol_Record *
+Protocol_Manager::get_each_friend (void)
+{
+ return this->ss->get_each_entry ();
+}
+
+/* Returns the number of friends. */
+
+int
+Protocol_Manager::friend_count (void)
+{
+ return this->ss->n_elems ();
+}
+
+/* Returns total number of users logged in throughout the system. */
+
+int
+Protocol_Manager::get_total_users (void)
+{
+ return Protocol_Manager::total_users;
+}
+
+void
+Protocol_Manager::increment_total_users (int remote_users)
+{
+ Protocol_Manager::total_users += remote_users;
+}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/Protocol_Manager.h b/apps/drwho/Protocol_Manager.h
new file mode 100644
index 00000000000..705a1e81657
--- /dev/null
+++ b/apps/drwho/Protocol_Manager.h
@@ -0,0 +1,86 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* A base class that consolidates friend management functionality
+ shared by both clients and servers. */
+
+#ifndef _FRIEND_MANAGER_H
+#define _FRIEND_MANAGER_H
+
+#include "ace/OS.h"
+#include "Options.h"
+#include "Search_Struct.h"
+#include "Protocol_Record.h"
+
+class Protocol_Manager
+{
+protected:
+ int total_users;
+ Search_Struct *ss;
+
+ int friend_count (void);
+
+ Drwho_Node *get_drwho_node (char *host_name, Drwho_Node *&head);
+ int get_total_users (void);
+ void increment_total_users (int remote_users = 1);
+
+ Protocol_Record *get_next_friend (void);
+ Protocol_Record *get_each_friend (void);
+
+ virtual Protocol_Record *insert_protocol_info (Protocol_Record &protocol_record) = 0;
+
+public:
+ Protocol_Manager (void);
+ virtual ~Protocol_Manager (void);
+
+ virtual int encode (char *packet, int &total_bytes) = 0;
+ virtual int decode (char *packet, int &total_bytes) = 0;
+};
+
+#ifdef __OPTIMIZE__
+inline
+Protocol_Manager::Protocol_Manager (void): total_users (0)
+{}
+
+inline
+Protocol_Manager::~Protocol_Manager (void)
+{
+ if (Options::DEBUG)
+ fprintf (stderr, "disposing Protocol_Manager\n");
+}
+
+/* Returns the next friend in the sequence of sorted friends. */
+
+inline Protocol_Record *
+Protocol_Manager::get_next_friend (void)
+{
+ return this->ss->get_next_entry ();
+}
+
+inline Protocol_Record *
+Protocol_Manager::get_each_friend (void)
+{
+ return this->ss->get_each_entry ();
+}
+
+/* Returns the number of friends. */
+
+inline int
+Protocol_Manager::friend_count (void)
+{
+ return this->ss->n_elems ();
+}
+
+inline int
+Protocol_Manager::get_total_users (void)
+{
+ return this->total_users;
+}
+
+inline void
+Protocol_Manager::increment_total_users (int remote_users)
+{
+ this->total_users += remote_users;
+}
+#endif /* __OPTIMIZE__ */
+#endif /* _FRIEND_MANAGER_H */
diff --git a/apps/drwho/Protocol_Record.cpp b/apps/drwho/Protocol_Record.cpp
new file mode 100644
index 00000000000..c62350f03ff
--- /dev/null
+++ b/apps/drwho/Protocol_Record.cpp
@@ -0,0 +1,79 @@
+// $Id$
+#include "Options.h"
+#include "Protocol_Record.h"
+
+/* Static initialization. */
+
+Drwho_Node Protocol_Record::drwho_node;
+
+Protocol_Record::~Protocol_Record (void)
+{
+ if (Options::get_opt (Options::DEBUG))
+ fprintf (stderr, "disposing Protocol_Record\n");
+
+ for (Drwho_Node *np = this->get_drwho_list (); np != 0; )
+ {
+ Drwho_Node *t = np;
+ np = np->next;
+ }
+}
+
+#ifndef __OPTIMIZE__
+Protocol_Record::Protocol_Record (void)
+ : is_active (0), drwho_list (0), key_name1 (0), key_name2 (0), next (0)
+{}
+
+Protocol_Record::Protocol_Record (int)
+ : is_active (0), drwho_list (&Protocol_Record::drwho_node), key_name1 (0), key_name2 (0), next (0)
+{}
+
+
+Protocol_Record::Protocol_Record (char *kn1, Protocol_Record *next)
+ : is_active (0), drwho_list (0), key_name2 (0)
+{
+ this->key_name1 = kn1;
+ this->next = next;
+}
+
+char *
+Protocol_Record::get_login (void)
+{
+ return this->key_name1;
+}
+
+char *
+Protocol_Record::set_login (char *str)
+{
+ return this->key_name1 = str;
+}
+
+char *
+Protocol_Record::get_real (void)
+{
+ return this->key_name2;
+}
+
+char *
+Protocol_Record::get_host (void)
+{
+ return this->key_name1;
+}
+
+char *
+Protocol_Record::set_host (char *str)
+{
+ return this->key_name1 = str;
+}
+
+char *
+Protocol_Record::set_real (char *str)
+{
+ return this->key_name2 = str;
+}
+
+Drwho_Node *
+Protocol_Record::get_drwho_list (void)
+{
+ return this->drwho_list;
+}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/Protocol_Record.h b/apps/drwho/Protocol_Record.h
new file mode 100644
index 00000000000..05afa16f8e6
--- /dev/null
+++ b/apps/drwho/Protocol_Record.h
@@ -0,0 +1,95 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Stores information about a single friend's status. */
+
+#ifndef _FRIEND_RECORD_H
+#define _FRIEND_RECORD_H
+
+#include "Drwho_Node.h"
+
+class Protocol_Record
+{
+public:
+ static Drwho_Node drwho_node;
+ char *key_name1;
+ char *key_name2;
+ Drwho_Node *drwho_list;
+ Protocol_Record *next;
+ int is_active;
+
+ Protocol_Record (void);
+ Protocol_Record (int use_dummy);
+ Protocol_Record (char *key_name1, Protocol_Record *next = 0);
+ ~Protocol_Record (void);
+ char *get_host (void);
+ char *set_host (char *str);
+ char *get_login (void);
+ char *set_login (char *str);
+ char *get_real (void);
+ char *set_real (char *str);
+ Drwho_Node *get_drwho_list (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+Protocol_Record::Protocol_Record (void)
+ : is_active (0), drwho_list (0), key_name1 (0), key_name2 (0), next (0)
+{}
+
+inline
+Protocol_Record::Protocol_Record (int use_dummy)
+ : is_active (0), drwho_list (&Protocol_Record::drwho_node), key_name1 (0), key_name2 (0), next (0)
+{}
+
+inline
+Protocol_Record::Protocol_Record (char *key_name1, Protocol_Record *next)
+ : is_active (0), drwho_list (0), key_name2 (0)
+{
+ this->key_name1 = key_name1;
+ this->next = next;
+}
+
+inline char *
+Protocol_Record::get_login (void)
+{
+ return this->key_name1;
+}
+
+inline char *
+Protocol_Record::set_login (char *str)
+{
+ return this->key_name1 = str;
+}
+
+inline char *
+Protocol_Record::get_real (void)
+{
+ return this->key_name2;
+}
+
+inline char *
+Protocol_Record::get_host (void)
+{
+ return this->key_name1;
+}
+
+inline char *
+Protocol_Record::set_host (char *str)
+{
+ return this->key_name1 = str;
+}
+
+inline char *
+Protocol_Record::set_real (char *str)
+{
+ return this->key_name2 = str;
+}
+
+inline Drwho_Node *
+Protocol_Record::get_drwho_list (void)
+{
+ return this->drwho_list;
+}
+#endif /* __OPTIMIZE__ */
+#endif /* _FRIEND_RECORD_H */
diff --git a/apps/drwho/Rwho_DB_Manager.cpp b/apps/drwho/Rwho_DB_Manager.cpp
new file mode 100644
index 00000000000..e67d6ded666
--- /dev/null
+++ b/apps/drwho/Rwho_DB_Manager.cpp
@@ -0,0 +1,104 @@
+// $Id$
+#include "global.h"
+#include "Options.h"
+#include "Rwho_DB_Manager.h"
+
+/* Change to the RWHO directory to speed up and simplify later
+ processing. This requires opening the directory
+ for reading with the directory iterator abstraction and then
+ skipping the first two files in the directory, which are assumed to
+ be "." and ".." (this function needs to be changed if this
+ assumption does not hold!) */
+
+RWho_DB_Manager::RWho_DB_Manager (void)
+ : number_of_users (0), current_user (0), rwho_dir_name (RWHODIR),
+ WHOD_HEADER_SIZE (sizeof host_data - sizeof host_data.wd_we)
+{
+ if (getcwd (this->original_pathname, MAXPATHLEN + 1) == 0)
+ perror (Options::program_name), exit (1);
+
+ if (chdir (this->rwho_dir_name) < 0)
+ perror (this->rwho_dir_name), exit (1);
+
+ this->rwho_dir.opendir (this->rwho_dir_name);
+
+ /* Skip "." and ".." */
+ this->rwho_dir.readdir ();
+ this->rwho_dir.readdir ();
+}
+
+/* The destructor cleans up the RWHOD_DIR handle. */
+
+RWho_DB_Manager::~RWho_DB_Manager (void)
+{
+ if (chdir (this->original_pathname) < 0)
+ perror (Options::program_name), exit (1);
+
+ if (Options::get_opt (Options::DEBUG))
+ fprintf (stderr, "disposing the RWho-Manager\n");
+}
+
+/* This procedure looks through the rwhod directory until it finds the next
+ valid user file.
+
+ The requirements for user files are:
+ 1) The file is at least MIN_HOST_DATA_SIZE bytes long
+ 2) It was received within the last MAX_HOST_TIMEOUT seconds
+
+ Return:
+ Are there any more hosts? */
+
+int
+RWho_DB_Manager::get_next_host (void)
+{
+ dirent *dir_ptr;
+ long current_time;
+
+ time (&current_time);
+
+ /* Go through each file in the directory looking for valid entries */
+
+ while ((dir_ptr = this->rwho_dir.readdir ()) != 0)
+ {
+ int user_file;
+ int host_data_length;
+
+ if ((user_file = open (dir_ptr->d_name, O_RDONLY)) < 0)
+ return -1;
+
+ host_data_length = read (user_file, (char *) &this->host_data, sizeof this->host_data);
+
+ if (host_data_length > WHOD_HEADER_SIZE && current_time - this->host_data.wd_recvtime < MAX_HOST_TIMEOUT)
+ {
+ this->current_user = 0;
+ this->number_of_users = (host_data_length - WHOD_HEADER_SIZE) / sizeof *this->host_data.wd_we;
+ close (user_file);
+ return 1; /* We found a good host, so return it */
+ }
+ else
+ close (user_file);
+ }
+
+ return 0; /* There are no more hosts, so return False */
+}
+
+/* Returns the next user's information. Note that for efficiency
+ only pointers are copied, i.e., this info must be used before we
+ call this function again. */
+
+int
+RWho_DB_Manager::get_next_user (Protocol_Record &protocol_record)
+{
+ /* Get the next host file if necessary */
+ if (this->current_user >= this->number_of_users && this->get_next_host () == 0)
+ return 0;
+
+ Drwho_Node *current_node = protocol_record.get_drwho_list ();
+
+ protocol_record.set_login (this->host_data.wd_we[current_user].we_utmp.out_name);
+ current_node->set_host_name (this->host_data.wd_hostname);
+ current_node->set_idle_time (this->host_data.wd_we[current_user].we_idle);
+ this->current_user++;
+
+ return 1;
+}
diff --git a/apps/drwho/Rwho_DB_Manager.h b/apps/drwho/Rwho_DB_Manager.h
new file mode 100644
index 00000000000..7925c695bd5
--- /dev/null
+++ b/apps/drwho/Rwho_DB_Manager.h
@@ -0,0 +1,31 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* This class returns the user/machine pairs one at a time from the rwho database. */
+
+#ifndef _RWHO_DB_MANAGER_H
+#define _RWHO_DB_MANAGER_H
+
+#include "rwhod.h"
+#include "Dirent.h"
+#include "Protocol_Record.h"
+
+class RWho_DB_Manager
+{
+private:
+ Dirent rwho_dir;
+ whod host_data;
+ int number_of_users;
+ int current_user;
+ const int WHOD_HEADER_SIZE;
+ char original_pathname[MAXPATHLEN + 1];
+ char *rwho_dir_name;
+
+ int get_next_host (void);
+
+public:
+ RWho_DB_Manager (void);
+ ~RWho_DB_Manager (void);
+ int get_next_user (Protocol_Record &protocol_record);
+};
+#endif /* _RWHO_DB_MANAGER_H */
diff --git a/apps/drwho/SL_Client.cpp b/apps/drwho/SL_Client.cpp
new file mode 100644
index 00000000000..d2c62c942c6
--- /dev/null
+++ b/apps/drwho/SL_Client.cpp
@@ -0,0 +1,14 @@
+// $Id$
+#include "Options.h"
+#include "SL_Client.h"
+
+#ifndef __OPTIMIZE__
+SL_Client::SL_Client (char *usr_name): Single_Lookup (usr_name)
+{}
+
+Protocol_Record *
+SL_Client::insert (char *, int)
+{
+ return this->frp;
+}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/SL_Client.h b/apps/drwho/SL_Client.h
new file mode 100644
index 00000000000..f00e9939f02
--- /dev/null
+++ b/apps/drwho/SL_Client.h
@@ -0,0 +1,29 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the client's single user lookup table abstraction. */
+
+#ifndef _SL_CLIENT_H
+#define _SL_CLIENT_H
+
+#include "Single_Lookup.h"
+
+class SL_Client : public Single_Lookup
+{
+public:
+ SL_Client (char *usr_name);
+ virtual Protocol_Record *insert (char *key_name, int max_len = MAXUSERIDNAMELEN);
+};
+
+#ifdef __OPTIMIZE__
+inline
+SL_Client::SL_Client (char *usr_name): Single_Lookup (usr_name)
+{}
+
+inline Protocol_Record *
+SL_Client::insert (char *key_name, int)
+{
+ return this->frp;
+}
+#endif /* __OPTIMIZE__ */
+#endif /* _SL_CLIENT_H */
diff --git a/apps/drwho/SL_Server.cpp b/apps/drwho/SL_Server.cpp
new file mode 100644
index 00000000000..a55a02323c6
--- /dev/null
+++ b/apps/drwho/SL_Server.cpp
@@ -0,0 +1,21 @@
+// $Id$
+#include "global.h"
+#include "SL_Server.h"
+
+#ifndef __OPTIMIZE__
+SL_Server::SL_Server (char *usr_name): Single_Lookup (usr_name)
+{}
+
+Protocol_Record *
+SL_Server::get_each_entry (void)
+{
+ Protocol_Record *frp = Single_Lookup::get_each_entry ();
+ return frp->get_drwho_list () == 0 ? 0 : frp;
+}
+
+Protocol_Record *
+SL_Server::insert (char *key_name, int max_len)
+{
+ return strncmp (key_name, this->frp->get_login (), max_len) == 0 ? this->frp : 0;
+}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/SL_Server.h b/apps/drwho/SL_Server.h
new file mode 100644
index 00000000000..55738c554e1
--- /dev/null
+++ b/apps/drwho/SL_Server.h
@@ -0,0 +1,37 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the server's single user lookup table abstraction. */
+
+#ifndef _SL_SERVER_H
+#define _SL_SERVER_H
+
+#include "Single_Lookup.h"
+
+class SL_Server : public Single_Lookup
+{
+public:
+ SL_Server (char *packet);
+ virtual Protocol_Record *insert (char *key_name, int max_len = MAXUSERIDNAMELEN);
+ virtual Protocol_Record *get_each_entry (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+SL_Server::SL_Server (char *usr_name): Single_Lookup (usr_name)
+{}
+
+inline Protocol_Record *
+SL_Server::get_each_entry (void)
+{
+ Protocol_Record *frp = Single_Lookup::get_each_entry ();
+ return frp->get_drwho_list () == 0 ? 0 : frp;
+}
+
+inline Protocol_Record *
+SL_Server::insert (char *key_name, int max_len)
+{
+ return strncmp (key_name, this->frp->get_login (), max_len) == 0 ? this->frp : 0;
+}
+#endif /* __OPTIMIZE__ */
+#endif /* _SL_SERVER_H */
diff --git a/apps/drwho/SML_Client.cpp b/apps/drwho/SML_Client.cpp
new file mode 100644
index 00000000000..b097064e156
--- /dev/null
+++ b/apps/drwho/SML_Client.cpp
@@ -0,0 +1,35 @@
+// $Id$
+#include "Options.h"
+#include "SML_Client.h"
+
+int
+SML_Client::receive (int)
+{
+ if (sml_server.mux (this->recv_packet, this->packet_length) < 0)
+ return -1;
+
+ if (this->demux (this->recv_packet, this->packet_length) < 0)
+ return -1;
+
+ return 1;
+}
+
+int
+SML_Client::send (void)
+{
+ if (this->mux (this->send_packet, this->packet_length) < 0)
+ return -1;
+
+ if (sml_server.demux (this->send_packet, this->packet_length) < 0)
+ return -1;
+
+ return 1;
+}
+
+#ifndef __OPTIMIZE__
+SML_Client::SML_Client (void)
+{}
+
+SML_Client::~SML_Client (void)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/SML_Client.h b/apps/drwho/SML_Client.h
new file mode 100644
index 00000000000..462310b99a8
--- /dev/null
+++ b/apps/drwho/SML_Client.h
@@ -0,0 +1,32 @@
+/* -*- C++ -*- */
+// $Id$
+
+#ifndef _SML_CLIENT_H
+#define _SML_CLIENT_H
+
+#include "SM_Client.h"
+#include "SML_Server.h"
+
+class SML_Client : public SM_Client
+{
+private:
+ SML_Server sml_server;
+ int packet_length;
+
+public:
+ SML_Client (void);
+ virtual ~SML_Client (void);
+ virtual int receive (int timeout = 0);
+ virtual int send (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+SML_Client::SML_Client (void)
+{}
+
+inline
+SML_Client::~SML_Client (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif /* _SML_CLIENT_H */
diff --git a/apps/drwho/SML_Server.cpp b/apps/drwho/SML_Server.cpp
new file mode 100644
index 00000000000..e1ddcb83990
--- /dev/null
+++ b/apps/drwho/SML_Server.cpp
@@ -0,0 +1,10 @@
+// $Id$
+#include "SML_Server.h"
+
+#ifndef __OPTIMIZE__
+SML_Server::SML_Server (void)
+{}
+
+SML_Server::~SML_Server (void)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/SML_Server.h b/apps/drwho/SML_Server.h
new file mode 100644
index 00000000000..b5ab3474a80
--- /dev/null
+++ b/apps/drwho/SML_Server.h
@@ -0,0 +1,25 @@
+/* -*- C++ -*- */
+// $Id$
+
+#ifndef _SML_SERVER_H
+#define _SML_SERVER_H
+
+#include "SM_Server.h"
+
+class SML_Server : public SM_Server
+{
+public:
+ SML_Server (void);
+ virtual ~SML_Server (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+SML_Server::SML_Server (void)
+{}
+
+inline
+SML_Server::~SML_Server (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif /* _SML_SERVER_H */
diff --git a/apps/drwho/SMR_Client.cpp b/apps/drwho/SMR_Client.cpp
new file mode 100644
index 00000000000..cd3d97717d5
--- /dev/null
+++ b/apps/drwho/SMR_Client.cpp
@@ -0,0 +1,19 @@
+// $Id$
+#include "Options.h"
+#include "new.h"
+#include "PMC_All.h"
+#include "PMC_Flo.h"
+#include "PMC_Usr.h"
+#include "PMC_Ruser.h"
+#include "SMR_Client.h"
+
+#ifndef __OPTIMIZE__
+SMR_Client::SMR_Client (short port_number)
+{
+ if (CM_Client::open (port_number) < 0)
+ perror (Options::program_name), exit (1);
+}
+
+SMR_Client::~SMR_Client (void)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/SMR_Client.h b/apps/drwho/SMR_Client.h
new file mode 100644
index 00000000000..11a8b7cbf9b
--- /dev/null
+++ b/apps/drwho/SMR_Client.h
@@ -0,0 +1,28 @@
+/* -*- C++ -*- */
+// $Id$
+
+#ifndef _SMR_CLIENT_H
+#define _SMR_CLIENT_H
+
+#include "SM_Client.h"
+
+class SMR_Client : public SM_Client
+{
+public:
+ SMR_Client (short port_number);
+ virtual ~SMR_Client (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+SMR_Client::SMR_Client (short port_number)
+{
+ if (CM_Client::open (port_number) < 0)
+ perror (Options::program_name), exit (1);
+}
+
+inline
+SMR_Client::~SMR_Client (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif /* _SMR_CLIENT_H */
diff --git a/apps/drwho/SMR_Server.cpp b/apps/drwho/SMR_Server.cpp
new file mode 100644
index 00000000000..0c43d480b86
--- /dev/null
+++ b/apps/drwho/SMR_Server.cpp
@@ -0,0 +1,14 @@
+// $Id$
+#include "Options.h"
+#include "SMR_Server.h"
+
+#ifndef __OPTIMIZE__
+SMR_Server::SMR_Server (short port_number)
+{
+ if (CM_Server::open (port_number) < 0)
+ perror (Options::program_name), exit (1);
+}
+
+SMR_Server::~SMR_Server (void)
+{}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/SMR_Server.h b/apps/drwho/SMR_Server.h
new file mode 100644
index 00000000000..29c4281af7d
--- /dev/null
+++ b/apps/drwho/SMR_Server.h
@@ -0,0 +1,28 @@
+/* -*- C++ -*- */
+// $Id$
+
+#ifndef _SMR_SERVER_H
+#define _SMR_SERVER_H
+
+#include "SM_Server.h"
+
+class SMR_Server : public SM_Server
+{
+public:
+ SMR_Server (short port_number);
+ ~SMR_Server (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+SMR_Server::SMR_Server (short port_number)
+{
+ if (CM_Server::open (port_number) < 0)
+ perror (Options::program_name), exit (1);
+}
+
+inline
+SMR_Server::~SMR_Server (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif /* _SMR_SERVER_H */
diff --git a/apps/drwho/SM_Client.cpp b/apps/drwho/SM_Client.cpp
new file mode 100644
index 00000000000..074684076c0
--- /dev/null
+++ b/apps/drwho/SM_Client.cpp
@@ -0,0 +1,61 @@
+// $Id$
+#include "Options.h"
+#include "new.h"
+#include "PMC_All.h"
+#include "PMC_Flo.h"
+#include "PMC_Usr.h"
+#include "PMC_Ruser.h"
+#include "SM_Client.h"
+
+/* Call-back function that invokes the appropriate decode function. */
+
+int
+SM_Client::demux (char *packet, int &packet_length)
+{
+ if (this->pm_client->decode (packet, packet_length) < 0)
+ return -1;
+ return 1;
+}
+
+/* Call-back function that invokes the appropriate encode function. */
+
+int
+SM_Client::mux (char *packet, int &packet_length)
+{
+ switch (Options::protocol_type)
+ {
+ case Options::PROTO_USR:
+ this->pm_client = new (PRIVATE_POOL) PMC_Usr (Options::user_name);
+ break;
+ case Options::PROTO_ALL:
+ this->pm_client = new (PRIVATE_POOL) PMC_All;
+ break;
+ case Options::PROTO_FLO:
+ this->pm_client = new (PRIVATE_POOL) PMC_Flo;
+ break;
+ case Options::PROTO_RUSER:
+ this->pm_client = new (PRIVATE_POOL) PMC_Ruser;
+ break;
+ default:
+ fprintf (stderr, "%s: bad protocol\n", Options::program_name);
+ return -1;
+ }
+
+ if (this->pm_client->encode (packet, packet_length) < 0)
+ return -1;
+ return 1;
+}
+
+#ifndef __OPTIMIZE__
+SM_Client::SM_Client (void)
+{}
+
+SM_Client::~SM_Client (void)
+{}
+
+void
+SM_Client::process (void)
+{
+ this->pm_client->process ();
+}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/SM_Client.h b/apps/drwho/SM_Client.h
new file mode 100644
index 00000000000..3c33f3bd45e
--- /dev/null
+++ b/apps/drwho/SM_Client.h
@@ -0,0 +1,39 @@
+/* -*- C++ -*- */
+// $Id$
+
+#ifndef _SM_CLIENT_H
+#define _SM_CLIENT_H
+
+#include "PM_Client.h"
+#include "CM_Client.h"
+#include "Select_Manager.h"
+
+class SM_Client : public Select_Manager, public CM_Client
+{
+private:
+ PM_Client *pm_client;
+
+public:
+ SM_Client (void);
+ virtual int mux (char *packet, int &packet_length);
+ virtual int demux (char *packet, int &packet_length);
+ virtual void process (void);
+ virtual ~SM_Client (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+SM_Client::SM_Client (void)
+{}
+
+inline
+SM_Client::~SM_Client (void)
+{}
+
+inline void
+SM_Client::process (void)
+{
+ this->pm_client->process ();
+}
+#endif /* __OPTIMIZE__ */
+#endif /* _SM_CLIENT_H */
diff --git a/apps/drwho/SM_Server.cpp b/apps/drwho/SM_Server.cpp
new file mode 100644
index 00000000000..8709f6132d4
--- /dev/null
+++ b/apps/drwho/SM_Server.cpp
@@ -0,0 +1,59 @@
+// $Id$
+#include "new.h"
+#include "Options.h"
+#include "PMS_All.h"
+#include "PMS_Flo.h"
+#include "PMS_Usr.h"
+#include "PMS_Ruser.h"
+#include "SM_Server.h"
+
+int
+SM_Server::demux (char *packet, int &packet_length)
+{
+ /* SUPPRESS 112 */
+ switch (GET_PACKET_TYPE (packet))
+ {
+ case Options::PROTO_USR:
+ this->pm_server = new (PRIVATE_POOL) PMS_Usr;
+ break;
+ case Options::PROTO_ALL:
+ this->pm_server = new (PRIVATE_POOL) PMS_All;
+ break;
+ case Options::PROTO_FLO:
+ this->pm_server = new (PRIVATE_POOL) PMS_Flo;
+ break;
+ case Options::PROTO_RUSER:
+ this->pm_server = new (PRIVATE_POOL) PMS_Ruser;
+ break;
+ default:
+ return -1;
+ }
+
+ if (pm_server->decode (SKIP_PACKET_TYPE (packet), SUBTRACT_PACKET_TYPE (packet_length)) < 0)
+ return -1;
+
+ if (pm_server->process () < 0)
+ return -1;
+
+ return 1;
+}
+
+int
+SM_Server::mux (char *packet, int &packet_length)
+{
+ int status = pm_server->encode (packet, packet_length);
+
+ /* Hum... should this really go here? */
+ if (Options::get_opt (Options::STAND_ALONE_SERVER))
+ release_memory ();
+ return status;
+}
+
+#ifndef __OPTIMIZE__
+SM_Server::SM_Server (void)
+{}
+
+SM_Server::~SM_Server (void)
+{}
+#endif /* __OPTIMIZE__ */
+
diff --git a/apps/drwho/SM_Server.h b/apps/drwho/SM_Server.h
new file mode 100644
index 00000000000..fbad338adf9
--- /dev/null
+++ b/apps/drwho/SM_Server.h
@@ -0,0 +1,32 @@
+/* -*- C++ -*- */
+// $Id$
+
+#ifndef _SM_SERVER_H
+#define _SM_SERVER_H
+
+#include "PM_Server.h"
+#include "CM_Server.h"
+#include "Select_Manager.h"
+
+class SM_Server : public Select_Manager, public CM_Server
+{
+private:
+ PM_Server *pm_server;
+
+public:
+ SM_Server (void);
+ virtual ~SM_Server (void);
+ virtual int mux (char *packet, int &packet_length);
+ virtual int demux (char *packet, int &packet_length);
+};
+
+#ifdef __OPTIMIZE__
+inline
+SM_Server::SM_Server (void)
+{}
+
+inline
+SM_Server::~SM_Server (void)
+{}
+#endif /* __OPTIMIZE__ */
+#endif /* _SM_SERVER_H */
diff --git a/apps/drwho/Search_Struct.cpp b/apps/drwho/Search_Struct.cpp
new file mode 100644
index 00000000000..eb1a52ba71e
--- /dev/null
+++ b/apps/drwho/Search_Struct.cpp
@@ -0,0 +1,20 @@
+// $Id$
+#include "Options.h"
+#include "Search_Struct.h"
+
+#ifndef __OPTIMIZE__
+Search_Struct::~Search_Struct (void)
+{
+ if (Options::get_opt (Options::DEBUG))
+ fprintf (stderr, "disposing Search_Struct\n");
+}
+
+Search_Struct::Search_Struct (void): count (0)
+{}
+
+int
+Search_Struct::n_elems (void)
+{
+ return this->count;
+}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/Search_Struct.h b/apps/drwho/Search_Struct.h
new file mode 100644
index 00000000000..e8f8e6b0a48
--- /dev/null
+++ b/apps/drwho/Search_Struct.h
@@ -0,0 +1,42 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides an "Abstract Base Class" lookup table abstraction that
+ stores and manipulates friend records. */
+
+#ifndef _SEARCH_STRUCT_H
+#define _SEARCH_STRUCT_H
+
+#include "Protocol_Record.h"
+
+class Search_Struct
+{
+protected:
+ int count;
+
+public:
+ Search_Struct (void);
+ virtual ~Search_Struct (void);
+ virtual int n_elems (void);
+
+ virtual Protocol_Record *insert (char *key_name, int max_len = MAXUSERIDNAMELEN) = 0;
+ virtual Protocol_Record *get_next_entry (void) = 0;
+ virtual Protocol_Record *get_each_entry (void) = 0;
+};
+
+#ifdef __OPTIMIZE__
+inline
+Search_Struct::~Search_Struct (void)
+{}
+
+inline
+Search_Struct::Search_Struct (void): count (0)
+{}
+
+inline int
+Search_Struct::n_elems (void)
+{
+ return this->count;
+}
+#endif /* __OPTIMIZE__ */
+#endif /* _SEARCH_STRUCT_H */
diff --git a/apps/drwho/Select_Manager.h b/apps/drwho/Select_Manager.h
new file mode 100644
index 00000000000..0c06d47dc3f
--- /dev/null
+++ b/apps/drwho/Select_Manager.h
@@ -0,0 +1,12 @@
+// $Id$
+/* -*- C++ -*- */
+#ifndef _SELECT_MANAGER_H
+#define _SELECT_MANAGER_H
+
+class Select_Manager
+{
+public:
+ virtual int mux (char *packet, int &packet_length) = 0 ;
+ virtual int demux (char *packet, int &packet_length) = 0;
+};
+#endif /* _SELECT_MANAGER_H */
diff --git a/apps/drwho/Single_Lookup.cpp b/apps/drwho/Single_Lookup.cpp
new file mode 100644
index 00000000000..55751170bc9
--- /dev/null
+++ b/apps/drwho/Single_Lookup.cpp
@@ -0,0 +1,29 @@
+// $Id$
+#include "Options.h"
+#include "new.h"
+#include "Single_Lookup.h"
+
+#ifndef __OPTIMIZE__
+Single_Lookup::Single_Lookup (char *usr_name)
+{
+ this->frp = new (PRIVATE_POOL) Protocol_Record (ACE::strnew (usr_name));
+}
+
+Single_Lookup::~Single_Lookup (void)
+{
+ if (Options::get_opt (Options::DEBUG))
+ fprintf (stderr, "disposing Single_Lookup\n");
+}
+
+Protocol_Record *
+Single_Lookup::get_each_entry (void)
+{
+ return this->frp;
+}
+
+Protocol_Record *
+Single_Lookup::get_next_entry (void)
+{
+ return this->get_each_entry ();
+}
+#endif /* __OPTIMIZE__ */
diff --git a/apps/drwho/Single_Lookup.h b/apps/drwho/Single_Lookup.h
new file mode 100644
index 00000000000..e114b172656
--- /dev/null
+++ b/apps/drwho/Single_Lookup.h
@@ -0,0 +1,51 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides the client's single user lookup table abstraction. */
+
+#ifndef _SINGLE_LOOKUP_H
+#define _SINGLE_LOOKUP_H
+
+#include "Options.h"
+#include "Search_Struct.h"
+
+class Single_Lookup : public Search_Struct
+{
+protected:
+ Protocol_Record *frp;
+
+public:
+ Single_Lookup (char *usr_name);
+ virtual ~Single_Lookup (void);
+ virtual Protocol_Record *insert (char *key_name, int max_len = MAXUSERIDNAMELEN) = 0;
+ virtual Protocol_Record *get_next_entry (void);
+ virtual Protocol_Record *get_each_entry (void);
+};
+
+#ifdef __OPTIMIZE__
+inline
+Single_Lookup::Single_Lookup (char *usr_name)
+{
+ this->frp = new Protocol_Record (ACE::strnew (usr_name));
+}
+
+inline
+Single_Lookup::~Single_Lookup (void)
+{
+ if (Options::DEBUG)
+ fprintf (stderr, "disposing Single_Lookup\n");
+}
+
+inline Protocol_Record *
+Single_Lookup::get_each_entry (void)
+{
+ return this->frp;
+}
+
+inline Protocol_Record *
+Single_Lookup::get_next_entry (void)
+{
+ return this->get_each_entry ();
+}
+#endif /* __OPTIMIZE__ */
+#endif /* _SINGLE_LOOKUP_H */
diff --git a/apps/drwho/client.cpp b/apps/drwho/client.cpp
new file mode 100644
index 00000000000..f1b51483a1e
--- /dev/null
+++ b/apps/drwho/client.cpp
@@ -0,0 +1,61 @@
+// $Id$
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// drwho
+//
+// = FILENAME
+// client.cpp
+//
+// = DESCRIPTION
+// Client driver program for drwho.
+//
+// = AUTHOR
+// Douglas C. Schmidt
+//
+// ============================================================================
+
+#include "ace/OS.h"
+#include "Options.h"
+#include "new.h"
+#include "SML_Client.h"
+#include "SMR_Client.h"
+
+// Factory function.
+
+static SM_Client *
+make_client (void)
+{
+ if (Options::get_opt (Options::REMOTE_USAGE) == 0)
+ return new (PRIVATE_POOL) SML_Client;
+ else
+ return new (PRIVATE_POOL) SMR_Client (Options::port_number);
+}
+
+int
+main (int argc, char *argv[])
+{
+ Options::set_options (argc, argv);
+
+ mark_memory ();
+
+ SM_Client *sm_client = make_client ();
+
+ if (sm_client->send () < 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ Options::program_name),
+ -1);
+
+ if (sm_client->receive (Options::max_server_timeout) < 0)
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%p\n",
+ Options::program_name),
+ -1);
+
+ sm_client->process ();
+
+ return 0;
+}
diff --git a/apps/drwho/global.h b/apps/drwho/global.h
new file mode 100644
index 00000000000..0352ca36e31
--- /dev/null
+++ b/apps/drwho/global.h
@@ -0,0 +1,35 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Here are all the declarations that are needed throughout the program. */
+
+#ifndef _GLOBAL_H
+#define _GLOBAL_H
+
+/* These constants are used throughout the program... */
+
+enum
+{
+ MAXUSERIDNAMELEN = 8,
+ MAX_USER_TIMEOUT = 300,
+ MAX_HOST_TIMEOUT = 300,
+#ifdef i386
+ UDP_PACKET_SIZE = 0x2000,
+#else
+ UDP_PACKET_SIZE = 0x4000,
+#endif
+ PORT_NUMBER = 12344
+/* MAXPATHLEN = 1024,
+ MAXHOSTNAMELEN = 64 + 1 */
+};
+
+/* Default name of file where friends info is stored. */
+#define FRIEND_FILE ".friends.dta"
+
+/* Default name where rwho info is stored. */
+#define RWHODIR "/usr/spool/rwho"
+
+/* Daemon creator. */
+extern void daemon_start (int ignsigcld);
+
+#endif /* _GLOBAL_H */
diff --git a/apps/drwho/new.cpp b/apps/drwho/new.cpp
new file mode 100644
index 00000000000..eb0668290d1
--- /dev/null
+++ b/apps/drwho/new.cpp
@@ -0,0 +1,215 @@
+// $Id$
+/* Provide a very fast dynamic memory management abstraction tuned for
+ drwho server characteristics. */
+
+#include "assert.h"
+#include "ace/OS.h"
+#include "Options.h"
+#include "new.h"
+
+#if 0
+/* Determine default alignment. If your C++ compiler does not
+ like this then try something like #define ALIGNMENT 8. */
+
+struct fooalign {char x; double d;};
+
+static int ALIGNMENT = ((char *)&((struct fooalign *) 0)->d - (char *)0);
+static int PAGE_SIZE = getpagesize ();
+#endif
+
+static const int ALIGNMENT = 8;
+static const int PAGE_SIZE = 4096;
+static const int debug = 1;
+static int use_pool = 0;
+
+static inline int
+max (int a, int b)
+{
+ return a >= b ? a : b;
+}
+
+/* The ALIGNMENT argument must be a power of two... */
+
+static inline int
+round (size_t size, int alignment)
+{
+ return size + alignment - 1 & ~(alignment - 1);
+}
+
+class Chunk_Manager
+{
+private:
+ struct Chunk
+ {
+ Chunk *next;
+ char *buf_cur;
+ char *buf_end;
+ int buf_size;
+ char buf_start[1];
+
+ int chunk_must_grow (size_t size);
+ void *get_n_bytes (size_t size);
+ int chunk_size (void);
+ void print_stats (int);
+ };
+
+ static void insert_free_chunk (Chunk *ptr);
+ static Chunk *check_free_list (size_t size);
+ static Chunk *make_new_chunk (size_t size, Chunk *next = 0);
+ static Chunk *free_list;
+ static Chunk *head;
+ static size_t default_chunk_size;
+
+public:
+ static void *alloc_bytes (size_t size);
+ static void release_chunks (void);
+};
+
+size_t Chunk_Manager::default_chunk_size = 4 * PAGE_SIZE;
+Chunk_Manager::Chunk *Chunk_Manager::free_list = 0;
+Chunk_Manager::Chunk *Chunk_Manager::head = 0;
+
+void
+#if defined (__GNUG__) || defined (SunOS5)
+Chunk_Manager::Chunk::print_stats (int size)
+#else
+Chunk::print_stats (int size)
+#endif
+{
+ fprintf (stderr, "buf_size = %d, bytes left = %d, bytes used = %d, bytes requested = %d\n",
+ this->buf_size, this->buf_end - this->buf_cur, this->buf_cur - this->buf_start, size);
+}
+
+int
+#if defined (__GNUG__) || defined (SunOS5)
+Chunk_Manager::Chunk::chunk_must_grow (size_t size)
+#else
+Chunk::chunk_must_grow (size_t size)
+#endif
+{
+ return this->buf_end - this->buf_cur < size;
+}
+
+void *
+#if defined (__GNUG__) || defined (SunOS5)
+Chunk_Manager::Chunk::get_n_bytes (size_t size)
+#else
+Chunk::get_n_bytes (size_t size)
+#endif
+{
+ void *temp = this->buf_cur;
+ this->buf_cur += size;
+ return temp;
+}
+
+int
+#if defined (__GNUG__) || defined (SunOS5)
+Chunk_Manager::Chunk::chunk_size (void)
+#else
+Chunk::chunk_size (void)
+#endif
+{
+ return this->buf_size;
+}
+
+void
+Chunk_Manager::insert_free_chunk (Chunk *ptr)
+{
+ for (Chunk **flpp = &Chunk_Manager::free_list; (*flpp) != 0 && (*flpp)->buf_size < ptr->buf_size; flpp = &(*flpp)->next)
+ ;
+
+ ptr->next = *flpp;
+ *flpp = ptr;
+}
+
+Chunk_Manager::Chunk *
+Chunk_Manager::check_free_list (size_t size)
+{
+
+ for (Chunk **flpp = &Chunk_Manager::free_list; (*flpp) != 0 && (*flpp)->buf_size < size; flpp = &(*flpp)->next)
+ ;
+
+ if (*flpp == 0)
+ return 0;
+ else
+ {
+ Chunk *flp = *flpp;
+ *flpp = (*flpp)->next;
+ return flp;
+ }
+}
+
+void
+Chunk_Manager::release_chunks (void)
+{
+ Chunk *tmp = Chunk_Manager::head;
+
+ while (tmp != 0)
+ {
+ Chunk *t = tmp;
+ tmp = tmp->next;
+ insert_free_chunk (t);
+ }
+
+ Chunk_Manager::head = 0;
+}
+
+Chunk_Manager::Chunk *
+Chunk_Manager::make_new_chunk (size_t size, Chunk *n)
+{
+ Chunk *free_chunk = Chunk_Manager::check_free_list (size = round (size, Chunk_Manager::default_chunk_size));
+
+ if (free_chunk == 0)
+ {
+ if ((free_chunk = (Chunk *) malloc (sizeof *free_chunk + size)) == 0)
+ return 0;
+
+ free_chunk->buf_size = size;
+ free_chunk->buf_end = free_chunk->buf_start + free_chunk->buf_size;
+ }
+ free_chunk->buf_cur = free_chunk->buf_start;
+ free_chunk->next = n;
+ return free_chunk;
+}
+
+void *
+Chunk_Manager::alloc_bytes (size_t size)
+{
+ size = round (size, ALIGNMENT);
+
+ if (Chunk_Manager::head == 0)
+ Chunk_Manager::head = Chunk_Manager::make_new_chunk (size);
+ else if (Chunk_Manager::head->chunk_must_grow (size))
+ Chunk_Manager::head = Chunk_Manager::make_new_chunk (max (Chunk_Manager::head->chunk_size () * 2, size), Chunk_Manager::head);
+
+// Chunk_Manager::head->print_stats (size);
+
+ return Chunk_Manager::head->get_n_bytes (size);
+}
+
+void *
+operator new (size_t size, New_Pool new_pool)
+{
+ if (::use_pool || new_pool == PRIVATE_POOL)
+ return Chunk_Manager::alloc_bytes (size);
+ else
+ return (void *) malloc (size);
+}
+void
+mark_memory (int start_using_the_pool)
+{
+ ::use_pool = start_using_the_pool;
+}
+
+void
+release_memory (void)
+{
+ Chunk_Manager::release_chunks ();
+}
+
+/* We need this deletion operator in order to make the linker happy. */
+
+void
+operator delete (void *)
+{
+}
diff --git a/apps/drwho/new.h b/apps/drwho/new.h
new file mode 100644
index 00000000000..6ad5eb11442
--- /dev/null
+++ b/apps/drwho/new.h
@@ -0,0 +1,27 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* Provides a fast, fixed-sized pool of memory. */
+
+#ifndef _NEW_H
+#define _NEW_H
+
+#include <stddef.h>
+
+enum New_Pool
+{
+ MALLOC_POOL = 1,
+ PRIVATE_POOL = 2
+};
+
+void *operator new (size_t size, New_Pool new_pool);
+
+void operator delete (void *);
+
+/* Release all the memory... */
+void release_memory (void);
+
+/* Set the mark for future memory allocation... */
+void mark_memory (int start_using_the_pool = 1);
+
+#endif /* _NEW_H */
diff --git a/apps/drwho/rwhod.h b/apps/drwho/rwhod.h
new file mode 100644
index 00000000000..d884f5cd27a
--- /dev/null
+++ b/apps/drwho/rwhod.h
@@ -0,0 +1,38 @@
+/* -*- C++ -*- */
+// $Id$
+
+/* The /usr/include/protocols/rwhod.h header breaks cfront 2.0... */
+
+#ifndef _RWHOD_H
+#define _RWHOD_H
+
+struct outmp
+{
+ char out_line[8]; /* tty name */
+ char out_name[8]; /* user id */
+ long out_time; /* time on */
+};
+
+struct whoent
+{
+ outmp we_utmp; /* active tty info */
+ int we_idle; /* tty idle time */
+};
+
+struct whod
+{
+ char wd_vers; /* protocol version # */
+ char wd_type; /* packet type, see below */
+ char wd_pad[2];
+ int wd_sendtime; /* time stamp by sender */
+ int wd_recvtime; /* time stamp applied by receiver */
+ char wd_hostname[32]; /* hosts's name */
+ int wd_loadav[3]; /* load average as in uptime */
+ int wd_boottime; /* time system booted */
+ whoent wd_we[1024 / sizeof (struct whoent)];
+};
+
+#define WHODVERSION 1
+#define WHODTYPE_STATUS 1 /* host status */
+
+#endif /* _RWHOD_H */
diff --git a/apps/drwho/server.cpp b/apps/drwho/server.cpp
new file mode 100644
index 00000000000..3ae1adb6919
--- /dev/null
+++ b/apps/drwho/server.cpp
@@ -0,0 +1,96 @@
+// $Id$
+/* Driver program for the server. Note that it is easy to reuse the
+ server for other distributed programs. Pretty much all that must
+ change are the functions registered with the communciations
+ manager. */
+
+#include "ace/OS.h"
+#include "Options.h"
+#include "new.h"
+#include "SMR_Server.h"
+
+static char *
+tstamp (void)
+{
+ long time_now;
+ char *temp;
+
+ time_now = time (0);
+ temp = asctime (localtime (&time_now));
+ temp[12] = 0;
+ return temp;
+}
+
+/* Catch the obvious signals and die with dignity... */
+
+static void
+exit_server (int sig)
+{
+ char buffer[80];
+ sprintf (buffer, "%s exiting on signal", tstamp ());
+ psignal (sig, buffer);
+ monitor (0);
+ exit (0);
+}
+
+/* Returns TRUE if the program was started by INETD. */
+
+static int
+started_by_inetd (void)
+{
+ /* SUPPRESS 175 */
+ sockaddr_in sin;
+ int size = sizeof sin;
+
+ return getsockname (0, (sockaddr *) &sin, &size) == 0;
+}
+
+/* Does the drwho service. */
+
+static void
+do_drwho (SMR_Server &smr_server)
+{
+ if (smr_server.receive () == -1)
+ perror (Options::program_name);
+
+ if (smr_server.send () == -1)
+ perror (Options::program_name);
+}
+
+/* If the server is started with any argument at all then it doesn't
+ fork off a child process to do the work. This is useful when
+ debugging! */
+
+int
+main (int argc, char *argv[])
+{
+ signal (SIGTERM, SIG_PF (exit_server));
+ signal (SIGINT, SIG_PF (exit_server));
+ signal (SIGQUIT, SIG_PF (exit_server));
+
+ Options::set_options (argc, argv);
+ Options::set_opt (Options::STAND_ALONE_SERVER);
+
+ int inetd_controlled = started_by_inetd ();
+
+ if (!inetd_controlled && Options::get_opt (Options::BE_A_DAEMON))
+ daemon_start (1);
+
+ mark_memory ();
+
+ SMR_Server smr_server (Options::port_number);
+
+ /* I'm not sure what this should do yet... */
+
+ if (inetd_controlled)
+ do_drwho (smr_server);
+ else
+ {
+
+ for (;;)
+ do_drwho (smr_server);
+
+ /* NOTREACHED */
+ }
+ exit (0);
+}