SMTP Server errors

Hey everyone,

I have an issue where email is working fine in our Windows environments but is blowing up in our AIX environments.

Here is the related functions that are getting called:

int get_smtp_line( void )
{
   char ch = '.';
   char in_data [MAXOUTLINE];
   char * index;
   int retval = 0;

   index = in_data;

   while (ch != '\n')
   {
      if ( (retval = gensock_getchar (SMTPSock, 0, &ch) ) )
      {
         gensock_error ("gensock_getchar", retval);
         return -1;
      }
      else
      {
         *index = ch;
         index++;
      }
   }


   return atoi(in_data);
}
int GENSOCK_EXPORT
gensock_getchar (socktag st, int wait, char FAR * ch)
{
   connection * conn;
   int retval = 0;

   conn = (connection *) st;
   if (!conn)
      return (ERR_NOT_A_SOCKET);

   if ((retval = conn->getchar(wait, ch)))
      return (retval);
   else
      return (0);
}

When I run this in AIX, ch stays as '\0', where in Windows it changes as expected. I'm completely lost on this. Any help?

The malfunction, whatever it may be, is probably in comm->getchar(). You haven't posted that class, so we can't tell what it is.

In fact, why not just post the code in general so we don't have to wheedle you for bits of it piecemeal, dragging out the process for days or weeks.

Certainly :slight_smile: (sorry in advance for the wall of code - I feel certain someone did a copy/paste for this years ago)

//mail_un.cpp

#ifdef OC_UNIX
#include <stdio.h>
#include <stdlib.h>

#include <amsios.h>
#include <string.h>
#include <time.h>
#include <amsdefs.h>
#include <mail.h> 
/* generic socket DLL support */
#include "gensocks.h"

#define MAXOUTLINE 255


int SMTPSock;


#define SERVER_SIZE    256     // #defines (bleah!) from Beverly Brown "beverly@datacube.com"
#define SENDER_SIZE    256
#define MAX_PATH    256
enum BOOL { FALSE1, TRUE1};

char SMTPHost[SERVER_SIZE];
char Sender[SENDER_SIZE];
char *Recipients;
char my_hostname[1024];
char *destination = "";
char *cc_list = "";
char *bcc_list = "";
char *loginname = "";
char *senderid = "";
char *subject = "";
int mime = 0;
int quiet = 0;


char *usage[] =
   {
      "Blat v1.5: WinNT console utility to mail a file via SMTP",
      "",
      "syntax:",
      "Blat <filename> -t <recipient> [optional switches (see below)]",
      "Blat -install <server addr> <sender's addr> [-q]",
      "Blat -h [-q]",
      "",
      "-install <server addr> <sender's addr>: set's default SMTP server and sender",
      "",
      "<filename>    : file with the message body ('-' for console input, end with ^Z)",
      "-t <recipient>: recipient list (comma separated)",
      "-s <subj>     : subject line",
      "-f <sender>   : overrides the default sender address (must be known to server)",
      "-i <addr>     : a 'From:' address, not necessarily known to the SMTP server.",
      "-c <recipient>: carbon copy recipient list (comma separated)",
      "-b <recipient>: blind carbon copy recipient list (comma separated)",
      "-h            : displays this help.",
      "-mime         : MIME Quoted-Printable Content-Transfer-Encoding.",
      "-q            : supresses *all* output.",
      "-server <addr>: overrides the default SMTP server to be used.",
      "",
      "Note that if the '-i' option is used, <sender> is included in 'Reply-to:'",
      "and 'Sender:' fields in the header of the message."
   };
const NMLINES = 22;

void
gensock_error (char * function, int retval)
{
   if ( ! quiet )
   {
      switch ( retval )
      {
         case 4001:
         cout << "Error: Malloc failed (possibly out of memory).";
         break;
         case 4002:
         cout << "Error: Error sending data.";
         break;
         case 4003:
         cout << "Error: Error initializing gensock.dll.";
         break;
         case 4004:
         cout << "Error: Version not supported.";
         break;
         case 4005:
         cout << "Error: The winsock version specified by gensock is not supported by this winsock.dll.";
         break;
         case 4006:
         cout << "Error: Network not ready.";
         break;
         case 4007:
         cout << "Error: Can't resolve (mailserver) hostname.";
         break;
         case 4008:
         cout << "Error: Can't create a socket (too many simultaneous links?)";
         break;
         case 4009:
         cout << "Error: Error reading socket.";
         break;
         case 4010:
         cout << "Error: Not a socket.";
         break;
         case 4011:
         cout << "Error: Busy.";
         break;
         case 4012:
         cout << "Error: Error closing socket.";
         break;
         case 4013:
         cout << "Error: Wait a bit (possible timeout).";
         break;
         case 4014:
         cout << "Error: Can't resolve service.";
         break;
         case 4015:
         cout << "Error: Can't connect to mailserver (timed out if winsock.dll error 10060)";
         break;
         case 4016:
         cout << "Error: Connection to mailserver was dropped.";
         break;
         case 4017:
         cout << "Error: Mail server refused connection.";
         break;
         default:
         cout << "error " << retval << " in function '" << function;
      }
   }
}




int open_smtp_socket( void )
{
   int retval;


   retval = gensock_connect ( SMTPHost, "smtp", &SMTPSock);

   if (retval)
   {
      if (retval == ERR_CANT_RESOLVE_SERVICE)
      {
         retval = gensock_connect (SMTPHost,
                                   "25",
                                   &SMTPSock);
         if (retval)
         {
            gensock_error ("gensock_connect", retval);
            return -1;
         }
      }
      // error other than can't resolve service
      else
      {
         gensock_error ("gensock_connect", retval);
         return -1;
      }
   }

   return 0;
}


int close_smtp_socket( void )
{
   int retval;

   if ( (retval = gensock_close (SMTPSock)) )
   {
      gensock_error ("gensock_close", retval);
      return -1;
   }

   return (0);
}

int get_smtp_line( void )
{
   char ch = '.';
   char in_data [MAXOUTLINE];
   char * index;
   int retval = 0;

   index = in_data;

   while (ch != '\n')
   {
      if ( (retval = gensock_getchar (SMTPSock, 0, &ch) ) )
      {
         gensock_error ("gensock_getchar", retval);
         return -1;
      }
      else
      {
         *index = ch;
         index++;
      }
   }


   return atoi(in_data);
}

int put_smtp_line( int sock, char * line, unsigned int nchars )
{
   int retval;

   if ( (retval = gensock_put_data (sock, line, (unsigned long) nchars)))
   {
      gensock_error ("gensock_put_data", retval);
      return -1;
   }
   return (0);
}

int putline_internal (int sock, char * line, unsigned int nchars)
{
   int retval;

   if ((retval =
            gensock_put_data (sock,
                              (char *) line,
                              (unsigned long) nchars)))
   {
      switch (retval)
      {
         case ERR_NOT_CONNECTED:
         gensock_error( "SMTP server has closed the connection", retval );
         break;

         default:
         gensock_error ("gensock_put_data", retval);
      }
      return -1;
   }
   return (0);
}

void smtp_error (char * message)
{
   if ( ! quiet )
      cout << message << "\n";
   put_smtp_line (SMTPSock, "QUIT\r\n", 6);
   close_smtp_socket();
}


// 'destination' is the address the message is to be sent to
// 'message' is a pointer to a null-terminated 'string' containing the
// entire text of the message.

int prepare_smtp_message(char * MailAddress, char * destination)
{
   char out_data[MAXOUTLINE];
   char str[1024];
   char *ptr;
   int len, startLen;

   if ( open_smtp_socket() )
      return -1;

   if ( get_smtp_line() != 220 )
   {
      smtp_error ("SMTP server error");
      return ( -1);
   }

   sprintf( out_data, "HELO %s\r\n", my_hostname);
   put_smtp_line( SMTPSock, out_data, strlen (out_data) );

   if ( get_smtp_line() != 250 )
   {
      smtp_error ("SMTP server error");
      return -1;
   }

   sprintf (out_data, "MAIL From:<%s>\r\n", loginname);
   put_smtp_line( SMTPSock, out_data, strlen (out_data) );

   if (get_smtp_line() != 250)
   {
      smtp_error ("The mail server doesn't like the sender name,\nhave you set your mail address correctly?");
      return -1;
   }

   // do a series of RCPT lines for each name in address line
   for (ptr = destination; *ptr; ptr += len + 1)
   {
      // if there's only one token left, then len will = startLen,
      // and we'll iterate once only
      startLen = strlen (ptr);
      if ((len = strcspn (ptr, " ,\n\t\r")) != startLen)
      {
         ptr[len] = '\0';            // replace delim with NULL char
         while (strchr (" ,\n\t\r", ptr[len + 1]))    // eat white space
            ptr[len++] = '\0';
      }

      sprintf (out_data, "RCPT To: <%s>\r\n", ptr);
      putline_internal( SMTPSock, out_data, strlen (out_data) );

      if (get_smtp_line() != 250)
      {
         sprintf (str, "The mail server doesn't like the name %s.\nHave you set the 'To: ' field correctly?", ptr);
         smtp_error (str);
         return -1;
      }

      if (len == startLen)    // last token, we're done
         break;
   }

   sprintf (out_data, "DATA\r\n");
   put_smtp_line (SMTPSock, out_data, strlen (out_data));

   if (get_smtp_line() != 354)
   {
      smtp_error ("Mail server error accepting message data");
      return -1;
   }

   return (0);

}

int transform_and_send_edit_data( int sock, char * editptr )
{
   char *index;
   char *header_end;
   char previous_char = 'x';
   unsigned int send_len;
   int retval;
   BOOL done = FALSE1;

   send_len = strlen(editptr);
   index = editptr;

   header_end = strstr (editptr, "\r\n\r\n");

   while (!done)
   {
      // room for extra char for double dot on end case
      while ((unsigned int) (index - editptr) < send_len)
      {
         switch (*index)
         {
            case '.':
            if (previous_char == '\n')
               /* send _two_ dots... */
               if ((retval = gensock_put_data_buffered (sock, index, 1)))
                  return (retval);
            if ((retval = gensock_put_data_buffered (sock, index, 1)))
               return (retval);
            break;
            case '\r':
            // watch for soft-breaks in the header, and ignore them
            if (index < header_end && (strncmp (index, "\r\r\n", 3) == 0))
               index += 2;
            else
               if (previous_char != '\r')
                  if ((retval = gensock_put_data_buffered (sock, index, 1)))
                     return (retval);
            // soft line-break (see EM_FMTLINES), skip extra CR */
            break;
            default:
            if ((retval = gensock_put_data_buffered (sock, index, 1)))
               return (retval);
         }
         previous_char = *index;
         index++;
      }
      if ( (unsigned int) (index - editptr) == send_len)
         done = TRUE1;
   }

   // this handles the case where the user doesn't end the last
   // line with a <return>

   if (editptr[send_len - 1] != '\n')
   {
      if ((retval = gensock_put_data_buffered (sock, "\r\n.\r\n", 5)))
         return (retval);
   }
   else
      if ((retval = gensock_put_data_buffered (sock, ".\r\n", 3)))
         return (retval);

   /* now make sure it's all sent... */
   if ((retval = gensock_put_data_flush(sock)))
      return (retval);
   return (TRUE);
}



int send_smtp_edit_data (char * message)
{
   transform_and_send_edit_data( SMTPSock, message );

   if (get_smtp_line() != 250)
   {
      smtp_error ("Message not accepted by server");
      return -1;
   }
   return (0);
}


int finish_smtp_message( void )
{
   return put_smtp_line( SMTPSock, "QUIT\r\n", 6 );
}





// MIME Quoted-Printable Content-Transfer-Encoding
#define MimeHexChar "0123456789ABCDEF";
void ConvertToQuotedPrintable(char ThisChar, int * CurrPos, char * buffer)
{
   int ThisValue;
   div_t result;
   // char buffer[8];
   char HexTable[17] = MimeHexChar;

   ThisValue = (256 + (unsigned int) ThisChar) % 256;

   if (ThisValue == 13)
   {
      sprintf( buffer, "%s", "\0" );
      return ;
   }
   else if (ThisValue == 10)
   {
      sprintf( buffer, "%s", "\r\n" );
      (*CurrPos) = 0;
      return ;
   }
   else if ((ThisValue < 33) |
            (ThisValue == 61) |
            (ThisValue > 126))
   {
      result = div(ThisValue, 16);
      buffer[0] = '=';
      (*CurrPos)++;
      buffer[1] = HexTable[result.quot];
      (*CurrPos)++;
      buffer[2] = HexTable[result.rem];
      (*CurrPos)++;
      buffer[3] = '\0';
   }
   else
   {
      buffer[0] = ThisChar;
      (*CurrPos)++;
      buffer[1] = '\0';
   }

   if (*CurrPos > 71)
   {
      strcat(buffer, "=\r\n");     /* Add soft line break */
      (*CurrPos) = 0;
   }
}


int send_mail ( char * in_buffer,
                char * in_recipients,
                char * in_subject,
                char * in_sender,
                char * in_copy_recipients,
                char * in_blind_recipients,
                char * in_server,
                char * in_hostname,
                char * in_loginname,
                char * error
              )    /* Array of environment variable strings    */
{

   int impersonating = 0;
   int penguin = 0;
   int i, j;
   int retcode;
   int hours, minutes;
   int dest_len, cc_len, bcc_len;


   // by default Blat is very noisy!
   quiet = 0;

   // by default Blat does not use mime Quoted-Printable Content-Transfer-Encoding!
   mime = 0;


   Sender[0] = '\0';
   SMTPHost[0] = '\0';


   // thanks to Beverly Brown "beverly@datacube.com" for
   // fixing the argument parsing, I "fixed" the brackets
   // to conform approximately to our "style"  :-)
   // Starts here

   subject = in_subject;

   cc_list = in_copy_recipients;

   bcc_list = in_blind_recipients;

   destination = in_recipients;

   strcpy(SMTPHost, in_server);

   loginname = in_loginname;

   //IR-GSAFX0569 set the senderid to in_sender rather than loginname
   senderid = in_sender;
   //senderid = loginname;

   strcpy(my_hostname, in_hostname);
   if ((SMTPHost[0] == '\0') || (loginname[0] == '\0'))
   {
      if ( ! quiet )
      {
         printf( "to set the SMTP server's address and the user name at that address do:\nblat -install server username\n");
         printf( "or use '-server <server name>' and '-f <user name>'\n");
         printf( "aborting, nothing sent\n" );
      }
      return 12;
   }

   if (destination)
      dest_len = strlen(destination);
   else
      dest_len = 0;

   if (cc_list)
      cc_len = strlen(cc_list);
   else
      cc_len = 0;

   if (bcc_list)
      bcc_len = strlen(bcc_list);
   else
      bcc_len = 0;

   char *temp = new char [ dest_len + \
                           cc_len + bcc_len + 4 ];
   // build the recipients list
   Recipients = new char [ dest_len + \
                           cc_len + bcc_len + 4 ];

   // Parse the "To:" line
   for (i = j = 0; i < (int) strlen(destination); i++)
   {
      // strip white space
      while (destination == ' ')
         i++;
      // look for comments in brackets, and omit
      if (destination == '(')
      {
         while (destination != ')')
            i++;
         i++;
      }
      // look for comments in quotes, and omit
      if (destination == '\'')
      {
         i++;
         while (destination != '\'')
            i++;
         i++;
      }

      temp[j++] = destination;
   }
   temp[j] = '\0';               // End of list added!
   strcpy( Recipients, temp);

   // Parse the "Cc:" line
   for (i = j = 0; i < cc_len; i++)
   {
      // strip white space
      while (cc_list == ' ')
         i++;
      // look for comments in brackets, and omit
      if (cc_list == '(')
      {
         while (cc_list != ')')
            i++;
         i++;
      }
      // look for comments in quotes, and omit
      if (cc_list == '\'')
      {
         i++;
         while (cc_list != '\'')
            i++;
         i++;
      }
      temp[j++] = cc_list;
   }
   temp[j] = '\0';               // End of list added!
   if ( cc_len > 0 )
   {
      strcat(Recipients, "," );
      strcat(Recipients, temp);
   }

   // Parse the "Bcc:" line
   for (i = j = 0; i < bcc_len; i++)
   {
      // strip white space
      while (bcc_list == ' ')
         i++;
      // look for comments in brackets, and omit
      if (bcc_list == '(')
      {
         while (bcc_list != ')')
            i++;
         i++;
      }
      // look for comments in quotes, and omit
      if (bcc_list == '\'')
      {
         i++;
         while (bcc_list != '\'')
            i++;
         i++;
      }
      temp[j++] = bcc_list;
   }
   temp[j] = '\0';               // End of list added!
   if ( bcc_len > 0 )
   {
      strcat(Recipients, "," );
      strcat(Recipients, temp);
   }


   // create a header for the message
   char tmpstr[256];
   char header[2048];
   int headerlen;

   sprintf( tmpstr, "From: %s\r\n", senderid );
   strcat( header, tmpstr );
   if ( impersonating )
   {
      sprintf( tmpstr, "Sender: %s\r\n", loginname );
      strcat( header, tmpstr );
      if (!(penguin == 1))
      {
         sprintf( tmpstr, "Reply-to: %s\r\n", loginname );
         strcat( header, tmpstr );
      }
   }
   if ( subject )
   {
      sprintf( tmpstr, "Subject: %s\r\n", subject );
      strcat( header, tmpstr );
   }

   sprintf( tmpstr, "To: %s\r\n", destination );
   strcat( header, tmpstr );
   if ( cc_list )
   {
      // Add line for the Carbon Copies
      sprintf( tmpstr, "Cc: %s\r\n", cc_list );
      strcat( header, tmpstr );
   }


   strcat( header, "X-Mailer: <WinNT's Blat ver 1.5>\r\n" );

   strcat (header, "\r\n");

   headerlen = strlen (header);

   long filesize = strlen(in_buffer);

   char *buffer = new char[(3 * (filesize + filesize / 72)) + headerlen + 1];
   char *tmpptr;

   // put the header at the top...
   strcpy ( buffer, header);
   // point to the end of header
   tmpptr = buffer + headerlen;

   strcpy (tmpptr, in_buffer);

   // make some noise about what we are doing
   if ( ! quiet )
   {
      if (subject)
         cout << "Subject:" << subject << '\n';
      if (loginname)
         cout << "Login name is " << loginname << '\n';
   }

   // send the message to the SMTP server!
   retcode = prepare_smtp_message( loginname, Recipients );
   if ( !retcode )
   {

      retcode = send_smtp_edit_data( buffer );
      if ( !retcode )
         finish_smtp_message();
      close_smtp_socket();
   }


   delete [] temp;
   delete [] buffer;
   delete [] Recipients;


   return (retcode);
}
#endif
//gensocks_un.cpp


#ifdef OC_UNIX 
// -*- C++ -*-
// generic socket DLL, winsock version
// disclaimer:  a C programmer wrote this.

// $Id: gensocks_un.cpp,v 1.12 2002/10/17 11:21:36Z aahamm Exp $

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>


extern "C"
{
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stropts.h>
#ifndef OC_LINUX_GCC
#ifndef OC_HPUX
#include <sys/conf.h>
#endif
#endif
#include <sys/time.h>
#include "gensocks.h"
}

#define SOCKET_BUFFER_SIZE    512
#ifdef OC_AIX_VACPP
#undef INADDR_NONE
#endif
#define INADDR_NONE        0
#define INVALID_SOCKET        -1
#define SOCKET_ERROR        -1

//
// ---------------------------------------------------------------------------
// container for a buffered SOCK_STREAM.

class connection
{
private:
   int    the_socket;
   char *in_buffer;
   char *out_buffer;
   unsigned int    in_index;
   unsigned int    out_index;
   unsigned int    in_buffer_total;
   unsigned int    out_buffer_total;
   unsigned int    last_winsock_error;
   fd_set    fds;
   struct timeval    timeout;

public:

   connection (void);
   ~connection (void);

   int get_connected (char * hostname, char * service);
   int get_socket(void)
   {
      return (the_socket);
   }
   int    get_buffer(int wait);
   int    close_conn (void);
   int    cc_getchar (int wait, char * ch);
   int    put_data (char * data, unsigned long length);
   int    put_data_buffered (char * data, unsigned long length);
   int    put_data_flush (void);
};

connection::connection (void)
{
   the_socket = 0;
   in_index = 0;
   out_index = 0;
   in_buffer_total = 0;
   out_buffer_total = 0;
   in_buffer = 0;

   in_buffer = new char[SOCKET_BUFFER_SIZE];
   out_buffer = new char[SOCKET_BUFFER_SIZE];

   last_winsock_error = 0;
}

connection::~connection (void)
{
   delete [] in_buffer;
   delete [] out_buffer;
}

int
gensock_is_a_number (char * string)
{
   while (*string)
   {
      if (!isdigit (*string))
      {
         return (0);
      }
      string++;
   }
   return (1);
}

//
// ---------------------------------------------------------------------------
//

int
connection::get_connected (char * hostname, char * service)
{
   struct hostent *    hostentry; /* from gethostbyname */
   struct servent *    serventry; /* from getservbyname */
   unsigned long ip_address;
   struct sockaddr_in    sa_in;
   int    our_port;
   struct linger NoLinger;
   int    retval, err_code;
   unsigned long    ioctl_blocking = 1;
   char    message[512];

   // if the ctor couldn't get a buffer
   if (!in_buffer || !out_buffer)
      return (ERR_CANT_MALLOC);

   // --------------------------------------------------
   // resolve the service name
   //

   // If they've specified a number, just use it.
   if (gensock_is_a_number (service))
   {
      char * tail;
      our_port = (int) strtol (service, &tail, 10);
      if (tail == service)
      {
         return (ERR_CANT_RESOLVE_SERVICE);
      }
      else
      {
         our_port = htons (our_port);
      }
   }
   else
   {
      // we have a name, we must resolve it.
      serventry = getservbyname (service, "tcp");

      if (serventry)
         our_port = serventry->s_port;
      else
         return (ERR_CANT_RESOLVE_SERVICE);
   }

   // --------------------------------------------------
   // resolve the hostname/ipaddress
   //
   // Assume only hostname
   //  if ((ip_address = inet_addr (hostname)) != INADDR_NONE) {
   //    sa_in.sin_addr.s_addr = ip_address;
   // }
   //  else {
   if ((hostentry = gethostbyname(hostname)) == NULL)
   {
      return (ERR_CANT_RESOLVE_HOSTNAME);
   }
   sa_in.sin_addr.s_addr = *(long *)hostentry->h_addr;
   // }


   // --------------------------------------------------
   // get a socket
   //

   if ((the_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
   {
      return (ERR_CANT_GET_SOCKET);
   }

   sa_in.sin_family = AF_INET;
   sa_in.sin_port = our_port;

   // set socket options.  DONTLINGER will give us a more graceful disconnect

   NoLinger.l_onoff = 0;
   setsockopt(the_socket,
              SOL_SOCKET,
              SO_LINGER,
              (char *) &NoLinger, sizeof(NoLinger));

   // get a connection

   retval = connect (the_socket, (struct sockaddr *) & sa_in,
                     sizeof(struct sockaddr_in));

   if (retval == SOCKET_ERROR)
   {
      return (ERR_CANT_CONNECT);
   }

#ifdef HA
   // Make this a non-blocking socket
   fcntl (the_socket, F_SETFL, O_NDELAY);
   // make the FD_SET and timeout structures for later operations...
#endif

   FD_ZERO (&fds);
   FD_SET (the_socket, &fds);

   // normal timeout, can be changed by the wait option.
   timeout.tv_sec = 0;
   timeout.tv_usec = 0;

   return (0);
}


//
//---------------------------------------------------------------------------
//
// The 'wait' parameter, if set, says to return WAIT_A_BIT
// if there's no data waiting to be read.

int
connection::get_buffer(int wait)
{
   int retval;
   int bytes_read = 0;
   unsigned long ready_to_read = 0;

   // Use select to see if data is waiting...

   FD_ZERO (&fds);
   FD_SET (the_socket, &fds);

   // if wait is set, we are polling, return immediately
   if (wait)
   {
      timeout.tv_sec = 0;
   }
   else
   {
      timeout.tv_sec = 0;
   }
#ifdef HA
   if ((retval = select (0, &fds, NULL, NULL, &timeout))
         == SOCKET_ERROR)
   {
      //printf ( "connection::get_buffer() unexpected error from select\n");
   }

   // if we don't want to wait


   if (!retval && wait)
   {
      return (WAIT_A_BIT);
   }
#endif
   // we have data waiting...
   bytes_read = recv (the_socket,
                      in_buffer,
                      SOCKET_BUFFER_SIZE,
                      0);

   // just in case.

   if (bytes_read == 0)
   {
      // connection terminated (semi-) gracefully by the other side
      return (ERR_NOT_CONNECTED);
   }

   if (bytes_read == SOCKET_ERROR)
   {
      //printf ("connection::get_buffer() unexpected error\n");

   }

   // reset buffer indices.


   in_buffer_total = bytes_read;
   in_index = 0;
   return (0);

}

//
//---------------------------------------------------------------------------
// get a character from this connection.
//

int
connection::cc_getchar(int wait, char * ch)
{
   int retval;

   if (in_index >= in_buffer_total)
   {
      if ((retval = get_buffer(wait)))
         return (retval);
   }
   *ch = in_buffer[in_index++];
   return (0);
}


//
//---------------------------------------------------------------------------
// FIXME: should try to handle the fact that send can only take
// an int, not an unsigned long.

int
connection::put_data (char * data, unsigned long length)
{
   int num_sent;
   int retval;

   FD_ZERO (&fds);
   FD_SET (the_socket, &fds);

   timeout.tv_sec = 0;
   while (length > 0)
   {
#ifdef HA
      if ((retval = select (0, NULL, &fds, NULL, &timeout)) == SOCKET_ERROR)
      {
         //printf ("connection::put_data() unexpected error from select \n");
      }
#endif

      num_sent = send (the_socket,
                       data,
                       length > 1024 ? 1024 : (int)length,
                       0);

      if (num_sent == SOCKET_ERROR)
      {
         //printf ( "connection::put_data() unexpected error from send()\n");
         return (ERR_SENDING_DATA);

      }
      else
      {
         length -= num_sent;
         data += num_sent;
      }
   }

   return (0);
}

//
//
// buffered output
//

int
connection::put_data_buffered (char * data, unsigned long length)
{
   unsigned int sorta_sent = 0;
   int retval;

   while (length)
   {
      if ((out_index + length) < SOCKET_BUFFER_SIZE)
      {
         // we won't overflow, simply copy into the buffer
         memcpy (out_buffer + out_index, data, (size_t) length);
         out_index += (unsigned int) length;
         length = 0;
      }
      else
      {
         unsigned int orphaned_chunk = SOCKET_BUFFER_SIZE - out_index;
         // we will overflow, handle it
         memcpy (out_buffer + out_index, data, orphaned_chunk);
         // send this buffer...
         if ((retval = put_data (out_buffer, SOCKET_BUFFER_SIZE)))
         {
            return (retval);
         }
         length -= orphaned_chunk;
         out_index = 0;
         data += orphaned_chunk;
      }
   }

   return (0);
}

int
connection::put_data_flush (void)
{
   int retval;

   if ((retval = put_data (out_buffer, out_index)))
      return (retval);
   else
      out_index = 0;

   return (0);
}

//
//---------------------------------------------------------------------------
//

int connection::close_conn (void)
{
   if ( close(the_socket) == SOCKET_ERROR)
      return (ERR_CLOSING);
   else
      return (0);
}



// ---------------------------------------------------------------------------
// C/DLL interface
//
connection *conn;
int gensock_connect (char * hostname,
                     char * service,
                     int * pst)
{

   int retval;

   conn = new connection;

   if ((retval = conn->get_connected (hostname, service)))
   {
      gensock_close(0);
      *pst = 0;
      return (0);
   }
   *pst = retval;

   return (retval);
}

//
//
//

int gensock_getchar (int st, int wait, char * ch)
{
   int retval = 0;
   //  connection *conn;

   //  conn = (connection *)st;

   if ((retval = conn->cc_getchar(wait, ch)))
      return (retval);
   else
      return (0);
}


//---------------------------------------------------------------------------
//
//

int gensock_put_data (int st, char * data, unsigned long length)
{
   //connection *conn;
   int retval = 0;

   // conn = (connection *)st;
   if ((retval = conn->put_data(data, length)))
      return (retval);

   return (0);
}

//---------------------------------------------------------------------------
//
//

int gensock_put_data_buffered (int st, char * data, unsigned long length)
{

   int retval;
   //connection *conn;

   //conn = (connection *) st;
   if ((retval = conn->put_data_buffered (data, length)))
      return (retval);

   return (0);
}

//---------------------------------------------------------------------------
//
//

int gensock_put_data_flush (int st)
{

   int retval = 0;
   // connection *conn;

   // conn = (connection *) st;

   if ((retval = conn->put_data_flush() ))
      return (retval);

   return (0);
}

//---------------------------------------------------------------------------
//
//
int gensock_gethostname (char * name, int namelen)
{
   int retval;
   //  if ((retval = gethostname(name, namelen))) {
   //   return (retval - 5000);
   //  }
   // else return (0);
   return (0);
}

//---------------------------------------------------------------------------
//
//

int gensock_close (int st)
{

   int retval;
   //connection *conn;

   //conn = (connection *) st;
   if ((retval = conn->close_conn()))
      return (retval);

   return (0);
}

#endif

connection::getchar is not in that code. It might be in the class header. There's a cc_getchar, but I'm not counting on that being the same.

Thank you for your help! I'm a little confused by what you mean though - where are you referring to the use of connection::getchar?