]> code.citadel.org Git - citadel.git/commitdiff
eeeeeeeeee
authorArt Cancro <ajc@citadel.org>
Mon, 10 May 1999 02:42:05 +0000 (02:42 +0000)
committerArt Cancro <ajc@citadel.org>
Mon, 10 May 1999 02:42:05 +0000 (02:42 +0000)
daphne/Makefile
daphne/citclient-bsdsockets.cpp [new file with mode: 0644]
daphne/citclient.cpp
daphne/includes.hpp
daphne/makefile.g95

index 152456864595d444d917658be5cb9f1f026cc085..c68016ec98539b3b237200d7f615fda788247bf6 100644 (file)
@@ -13,11 +13,11 @@ all: daphne
 
 daphne: main.o citclient.o userlogin.o testwindow.o who.o \
        utils.o express_message.o send_express.o prefs.o \
-       roomtree.o roomview.o tcp_sockets.o message.o enter.o \
+       roomtree.o roomview.o message.o enter.o \
        selectuser.o servprops.o
        c++ main.o citclient.o userlogin.o testwindow.o who.o \
        utils.o express_message.o send_express.o prefs.o \
-       roomtree.o roomview.o tcp_sockets.o message.o enter.o \
+       roomtree.o roomview.o message.o enter.o \
        selectuser.o servprops.o \
        $(LFLAGS) -o daphne
 
diff --git a/daphne/citclient-bsdsockets.cpp b/daphne/citclient-bsdsockets.cpp
new file mode 100644 (file)
index 0000000..6b5809f
--- /dev/null
@@ -0,0 +1,312 @@
+
+#include "includes.hpp"
+#include <unistd.h>
+
+
+//  
+//     TRANSPORT LAYER OPERATIONS
+//
+
+// Attach to the Citadel server
+// FIX (add check for not allowed to log in)
+int CitClient::attach(wxString host, wxString port) {
+       wxString ServerReady;
+
+       if (sock.is_connected())
+               sock.detach();
+       if (sock.attach(host, port)==0) {
+               serv_gets(ServerReady);
+               initialize_session();
+
+               curr_host = host;       // Remember host and port, in case
+               curr_port = port;       // we need to auto-reconnect later
+
+               return(0);
+       }
+       else return(1);
+
+}
+
+
+// constructor
+CitClient::CitClient(void) {
+       (void)new keepalive(this);
+}
+
+
+// destructor
+CitClient::~CitClient(void) {
+       // Be nice and log out from the server if it's still connected
+       sock.detach();
+}
+
+void CitClient::detach(void) {
+       wxString buf;
+
+       if (sock.is_connected()) {
+               serv_puts("QUIT");
+               serv_gets(buf);
+               sock.detach();
+       }
+}
+
+
+// Is this client connected?  Simply return the IsConnected status of sock.
+bool CitClient::IsConnected(void) {
+       return sock.is_connected();
+}
+
+
+
+// Read a line of text from the server
+void CitClient::serv_gets(wxString& buf) {
+       char charbuf[256];
+       
+       sock.serv_gets(charbuf);
+       buf = charbuf;
+}
+
+
+// Write a line of text to the server
+void CitClient::serv_puts(wxString buf) {
+       sock.serv_puts(buf);
+}
+
+
+//
+//             SESSION LAYER OPERATIONS
+//
+
+
+// Server transaction (returns first digit of server response code)
+int CitClient::serv_trans(
+                       wxString& command,
+                       wxString& response,
+                       wxString& xferbuf,
+                       wxString desired_room
+                       ) {
+
+        int first_digit, i, pos;
+       wxString buf, pw, junk;
+       bool express_messages_waiting = FALSE;
+
+       // If the caller specified that this transaction must take place
+       // in a particular room, make sure we're in that room.
+       if (desired_room.Length() > 0) {
+               if (desired_room.CmpNoCase(CurrentRoom) != 0) {
+                       pw = "";
+                       GotoRoom(desired_room, pw, junk);
+               }
+       }
+
+
+       // If a mutex is to be wrapped around this function in the future,
+       // it must begin HERE.
+
+       serv_puts(command);
+       
+       if (IsConnected() == FALSE) {
+               reconnect_session();
+               serv_puts(command);
+       }
+
+       serv_gets(response);
+
+       first_digit = (response.GetChar(0)) - '0';
+
+       if (response.GetChar(3) == '*')
+               express_messages_waiting = TRUE;
+
+       if (first_digit == 1) {                 // LISTING_FOLLOWS
+               xferbuf.Empty();
+               while (serv_gets(buf), buf != "000") {
+                       xferbuf.Append(buf + "\n");
+               }
+       } else if (first_digit == 4) {          // SEND_LISTING
+               buf = xferbuf;
+               while (buf.Length() > 0) {
+                       pos = buf.Find('\n', FALSE);
+                       if ((pos < 0) && (buf.Length() < 250)) {
+                               serv_puts(buf + "\n");
+                               buf.Empty();
+                       } else if ((pos < 250) && (pos >= 0)) {
+                               serv_puts(buf.Left(pos+1));
+                               buf = buf.Mid(pos+1);
+                       } else {
+                               pos = buf.Left(250).Find(' ', TRUE);
+                               if ((pos < 250) && (pos >= 0)) {
+                                       serv_puts(buf.Left(pos) + "\n");
+                                       buf = buf.Mid(pos+1);
+                               } else {
+                                       serv_puts(buf.Left(250) + "\n");
+                                       buf = buf.Mid(pos);
+                               }
+                       }
+               }
+               serv_puts("000");
+       }
+
+       // If a mutex is to be wrapped around this function in the future,
+       // it must end HERE.
+
+       if (express_messages_waiting) {
+               download_express_messages();
+       }
+
+       return first_digit;
+}
+
+// Shorter forms of serv_trans()
+int CitClient::serv_trans(
+                       wxString& command,
+                       wxString& response,
+                       wxString& xferbuf
+                       ) {
+       return serv_trans(command, response, xferbuf, "");
+}
+
+int CitClient::serv_trans(wxString& command, wxString& response) {
+       wxString junklist;
+       return serv_trans(command, response, junklist);
+}
+
+int CitClient::serv_trans(wxString& command) {
+       wxString junkbuf;
+       return serv_trans(command, junkbuf);
+}
+
+//
+//             PRESENTATION LAYER OPERATIONS
+//
+
+
+void CitClient::download_express_messages(void) {
+       wxString sendcmd, recvcmd, x_user, x_sys;
+       wxString xferbuf;
+
+       sendcmd = "GEXP";
+       while (serv_trans(sendcmd, recvcmd, xferbuf) == 1) {
+               extract(x_user, recvcmd, 3);
+               extract(x_sys, recvcmd, 4);
+               (void)new express_message(this, x_user, x_sys, xferbuf);
+       }
+}
+
+
+
+// Set up some things that we do at the beginning of every session
+void CitClient::initialize_session(void)  {
+       wxString info;
+       wxString sendcmd;
+       wxString recvcmd;
+       int i, pos;
+       wxString *infoptr;
+       wxString infoline;
+
+       CurrentRoom = "";
+
+       sendcmd = "IDEN 0|6|001|Daphne";
+       serv_trans(sendcmd);
+
+       sendcmd = "INFO";
+       if (serv_trans(sendcmd, recvcmd, info)==1) {
+               i = 0;
+               while (pos = info.Find('\n', FALSE),  (pos >= 0) ) {
+                       infoline = info.Left(pos);
+                       info = info.Mid(pos+1);
+                       switch(i) {
+
+                       case 0:         SessionID       = atoi(infoline);
+                       case 1:         NodeName        = infoline;
+                       case 2:         HumanNode       = infoline;
+                       case 3:         FQDN            = infoline;
+                       case 4:         ServerSoftware  = infoline;
+                       case 5:         ServerRev       = atoi(infoline);
+                       case 6:         GeoLocation     = infoline;
+                       case 7:         SysAdmin        = infoline;
+                       case 8:         ServerType      = atoi(infoline);
+                       case 9:         MorePrompt      = infoline;
+                       case 10:        UseFloors       = ((atoi(infoline)>0)
+                                                       ? TRUE : FALSE);
+                       case 11:        PagingLevel     = atoi(infoline);
+
+                       ++i;
+                       }
+               }
+       }
+}
+
+
+
+// Goto a room
+
+bool CitClient::GotoRoom(wxString roomname, wxString password,
+                       wxString& server_response) {
+       int retval;
+       wxString sendcmd, recvcmd;
+
+       sendcmd = "GOTO " + roomname + "|" + password;
+       retval = serv_trans(sendcmd, recvcmd);
+       server_response = recvcmd;
+
+       if (retval != 2) return FALSE;
+
+       extract(CurrentRoom, recvcmd.Mid(4), 0);
+       BigMDI->SetStatusText(CurrentRoom, 2);
+       return TRUE;
+}
+
+
+
+// Reconnect a broken session
+
+void CitClient::reconnect_session(void) {
+       wxString sendcmd;
+
+       CurrentRoom = "__ This is not the name of any valid room __";
+
+       // Give a crashed server some time to restart
+       sleep(5);
+
+       if (attach(curr_host, curr_port) != 0) {
+               // FIX do this more elegantly
+               cout << "Could not re-establish session (1)\n";
+       }
+
+       sendcmd = "USER " + curr_user;
+       if (serv_trans(sendcmd) != 3) {
+               // FIX do this more elegantly
+               cout << "Could not re-establish session (2)\n";
+       }
+
+       sendcmd = "PASS " + curr_pass;
+       if (serv_trans(sendcmd) != 2) {
+               // FIX do this more elegantly
+               cout << "Could not re-establish session (3)\n";
+       }
+}
+
+
+
+
+
+
+// This is a simple timer that periodically wakes up and sends a NOOP to the
+// server.  This accomplishes two things: it keeps the server connection
+// alive by trickling some data through when it's otherwise idle, and it allows
+// the "check for express messages" loop to activate if it has to.
+
+keepalive::keepalive(CitClient *sock)
+       : wxTimer() {
+
+       which_sock = sock;              // Know which instance to refresh
+       Start(15000, FALSE);            // Call every 15 seconds
+}
+
+
+void keepalive::Notify(void) {
+       if (which_sock->IsConnected()) {
+               wxString noop = "NOOP";
+               which_sock->serv_trans(noop);
+       }
+}
index 6b5809f9d96ad1fbacf5361b181bed7310311a98..c9fbb7562f39e19f561ddb978c416ed4dc4e49c6 100644 (file)
@@ -1,35 +1,68 @@
-
 #include "includes.hpp"
-#include <unistd.h>
-
 
 //  
 //     TRANSPORT LAYER OPERATIONS
 //
 
+
+
+/*
+ * Define a new derived SocketClient
+ */
+class MyClient: public wxSocketClient
+{
+public:
+       void OnNotify(wxRequestNotify WXUNUSED(flags)) {
+               cout << "Got An Event (tm)\n";
+       }
+};
+
+
+
+
+
+
+
+
 // Attach to the Citadel server
 // FIX (add check for not allowed to log in)
 int CitClient::attach(wxString host, wxString port) {
        wxString ServerReady;
-
-       if (sock.is_connected())
-               sock.detach();
-       if (sock.attach(host, port)==0) {
-               serv_gets(ServerReady);
-               initialize_session();
-
+       wxIPV4address addr;
+
+        if (sock->IsConnected())
+        sock->Close();
+
+        addr.Hostname(host);
+        addr.Service(port);
+        sock->SetNotify(0);
+        sock->Connect(addr, TRUE);
+        if (sock->IsConnected()) {
+                cout << "Connect succeeded\n" ;
+                serv_gets(ServerReady);
+                initialize_session();
                curr_host = host;       // Remember host and port, in case
                curr_port = port;       // we need to auto-reconnect later
-
-               return(0);
-       }
-       else return(1);
-
+                return(0);
+        } else {
+                cout << "Connect failed\n" ;
+                return(1);
+        }
 }
 
 
 // constructor
 CitClient::CitClient(void) {
+
+        wxSocketHandler::Master();
+        sock = new MyClient();
+
+       // The WAITALL flag causes reads to block.  Don't use it.
+        // sock->SetFlags(wxSocketBase::WAITALL);
+
+        wxSocketHandler::Master().Register(sock);
+        sock->SetNotify(wxSocketBase::REQ_LOST);
+
        (void)new keepalive(this);
 }
 
@@ -37,42 +70,77 @@ CitClient::CitClient(void) {
 // destructor
 CitClient::~CitClient(void) {
        // Be nice and log out from the server if it's still connected
-       sock.detach();
+       sock->Close();
 }
 
+
+
 void CitClient::detach(void) {
-       wxString buf;
+        wxString buf;
 
-       if (sock.is_connected()) {
-               serv_puts("QUIT");
-               serv_gets(buf);
-               sock.detach();
-       }
+        if (sock->IsConnected()) {
+                serv_puts("QUIT");
+                serv_gets(buf);
+                sock->Close();
+        }
 }
 
 
+
 // Is this client connected?  Simply return the IsConnected status of sock.
 bool CitClient::IsConnected(void) {
-       return sock.is_connected();
+        return sock->IsConnected();
 }
 
 
 
+
+
 // Read a line of text from the server
 void CitClient::serv_gets(wxString& buf) {
-       char charbuf[256];
-       
-       sock.serv_gets(charbuf);
+       static char charbuf[512];
+       static size_t nbytes = 0;
+       int i;
+       int nl_pos = (-1);
+
+       do {
+               sock->Read(&charbuf[nbytes], (sizeof(charbuf)-nbytes) );
+               nbytes += sock->LastCount();
+               for (i=nbytes; i>=0; --i)
+                       if (charbuf[i] == 10) nl_pos = i;
+       } while (nl_pos < 0);
+
+       charbuf[nbytes] = 0;
+       charbuf[nl_pos] = 0;
+
        buf = charbuf;
+       strcpy(charbuf, &charbuf[nl_pos + 1]);
+       nbytes = nbytes - (nl_pos + 1);
+
+       cout << "> " << buf << "(len=" << nl_pos << ")\n";
 }
 
 
+
+
+
+
 // Write a line of text to the server
 void CitClient::serv_puts(wxString buf) {
-       sock.serv_puts(buf);
+
+        cout << "< " << buf << "\n" ;
+        sock->Write((const char *)buf, buf.Len());
+        sock->Write("\n", 1);
 }
 
 
+
+
+
+
+
+
+
 //
 //             SESSION LAYER OPERATIONS
 //
@@ -102,10 +170,14 @@ int CitClient::serv_trans(
 
        // If a mutex is to be wrapped around this function in the future,
        // it must begin HERE.
+       cout << "Beginning transaction\n";
+       wxBeginBusyCursor();
+       Critter.Enter();
 
        serv_puts(command);
        
        if (IsConnected() == FALSE) {
+               wxSleep(5);     // Give a crashed server some time to restart
                reconnect_session();
                serv_puts(command);
        }
@@ -148,11 +220,16 @@ int CitClient::serv_trans(
 
        // If a mutex is to be wrapped around this function in the future,
        // it must end HERE.
+       cout << "Ending transaction...\n";
+       Critter.Leave();
+       wxEndBusyCursor();
+       cout << "...done.\n";
 
        if (express_messages_waiting) {
                download_express_messages();
        }
 
+       cout << "serv_trans() returning " << first_digit << "\n";
        return first_digit;
 }
 
@@ -265,9 +342,6 @@ void CitClient::reconnect_session(void) {
 
        CurrentRoom = "__ This is not the name of any valid room __";
 
-       // Give a crashed server some time to restart
-       sleep(5);
-
        if (attach(curr_host, curr_port) != 0) {
                // FIX do this more elegantly
                cout << "Could not re-establish session (1)\n";
index 5f8b8de6f1f1a92be68fa0c77f1f142c0325d4f6..eb8bf9615669b6a08aef783d639d9ed6e4c87779 100644 (file)
@@ -1,12 +1,13 @@
-#include <wx/wx.h>
+#include <wx/wx.h>             // General-purpose wxWin header
 #include <wx/listctrl.h>
-#include <wx/socket.h>
+#include <wx/socket.h>         // TCP socket client
 #include <wx/log.h>
 #include <wx/imaglist.h>
 #include <wx/treectrl.h>
 #include <wx/toolbar.h>
-#include <wx/tokenzr.h>
-#include <wxhtml/wxhtml.h>
+#include <wx/tokenzr.h>                // For the string tokenizer
+#include <wx/thread.h>         // No threads, but we need wxCriticalSection
+#include <wxhtml/wxhtml.h>     // Vaclav Slavik's HTML display widget
 
 #define MAXFLOORS      128
 #define DEFAULT_HOST   "uncnsrd.mt-kisco.ny.us"
 
 
 
-// TCPsocket represents a socket-level TCP connection to a server.
-class TCPsocket {
-public:
-       TCPsocket::TCPsocket(void);
-       int attach(const char *, const char *);
-       void detach(void);
-       void serv_read(char *, int);
-       void serv_write(char *, int);
-       void serv_gets(char *);
-       void serv_puts(const char *);
-       bool is_connected(void);
-private:
-       int serv_sock;
-       int connectsock(const char *, const char *, const char *);
-       static void timeout(int);
-};
-
-
-
 // CitClient represents an application-level connection to a Citadel server.
+class MyClient;
 class CitClient {
-       friend TCPsocket::timeout(int);
 public:
        CitClient(void);
        ~CitClient(void);
@@ -105,16 +87,15 @@ public:
        wxString CurrentRoom;
 
 private:
-       TCPsocket sock;                                 // transport layer
+       MyClient *sock;                                 // transport layer
+       wxCriticalSection Critter;
        void serv_gets(wxString& buf);                  // session layer
        void serv_puts(wxString buf);                   // session layer
        void reconnect_session(void);                   // session layer
        void download_express_messages(void);           // presentation layer
        void initialize_session(void);                  // presentation layer
-
        wxString curr_host;
        wxString curr_port;
-
 };
 
 
index 177895dcdb5277eca682d876046358181f56d3bd..334d4fc62094f1c710eab91c75f20ca39ae5c1c2 100644 (file)
@@ -7,7 +7,7 @@ TARGET          = daphne
 
 MY_OBJECTS     = citclient.o enter.o express_message.o main.o message.o \
                prefs.o roomtree.o roomview.o selectuser.o send_express.o \
-               servprops.o tcp_sockets.o testwindow.o userlogin.o \
+               servprops.o testwindow.o userlogin.o \
                utils.o who.o
 
 MY_LIBS         = $(WXHTMLDIR)/lib/libwxhtml.a