      /********************************************************/
      /*                   Widget-Builder               (3)   */
      /* This program was written by Brian R. Gardner, 1988.  */
      /* It was created as a visual, easy to use, technique   */
      /* for rapid proto-typing of user interfaces. It allows */
      /* its user to design the layout of an X-window based   */
      /* user interface, complete with sub-windows, buttons,  */
      /* labels, and other "widgets". This program will also  */
      /* serve as a programmer's aid by writing out to a file */
      /* the source code required to re-generate the created  */
      /* visual user interface. The code generated is usually */
      /* substantial, reflecting immense savings in the time  */
      /* neccessary to program using X-windows.               */
      /*    Note that this program is only a simple test      */
      /* version. It was the author's first introduction to   */
      /* the Athena environment, as well as X-windows and the */
      /*  X-Toolkit. It was written in 2 weeks.               */
      /*    This was written under the roof of Project Athena */
      /* at Massachusetts Institute of Technology, by         */
      /* Brian Gardner (DEC), and hence reasonably available. */
      /* Read that as "FREE"         :-)                      */
      /* with the usual friendly restrictions.                */
      /********************************************************/

     /************************************************************/
     /* Copyright 1988, Massachusetts Institute of Technology.   */
     /* See X(1) for a full statement of rights and permissions. */
     /************************************************************/

#include <string.h>
#include "wb_include.h"
#include "mailbufferP.h"

/****************************************************************/
    /* Dummy out this function for now. */
    /* Its not written, yet.            */

#define AlMB_encoded_string(str, delimeter)  str

/****************************************************************/

MailBuffer *AlMB_create()
  { MailBuffer *buffer;

    buffer = (MailBuffer *) calloc(sizeof(MailBuffer), 1);
    
    buffer->buffer = (char *) calloc(80, 1);
    buffer->buflen = 80;
    buffer->bufindex = 0;
    buffer->column = 0;

    return(buffer);

  };       /* end of AlMB_create()  */

/****************************************************************/

MailBuffer *MBcreate_from_file(filename)
     char *filename;
 { MailBuffer *buffer;
   FILE *fp;
   struct stat stbuf;
   int size;

   WBdebug(printf(">> Entering: MBcreate_from_file()\n"));
   if (filename == NULL)
     {
       WBdebug(printf("<< Exiting: MBcreate_from_file(): filename = NULL\n"));
       return(NULL);    /* no filename given */
     }
   if (stat(filename, &stbuf) == -1)
     {
       WBdebug(printf(
     "<< Exiting: MBcreate_from_file(): File doesn't exist (filename = '%s'\n",
		      filename));
       return(NULL);    /* no such file exists */
     }
   else if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
     {
       WBdebug(printf(
"<< Exiting: MBcreate_from_file(): directory was specified: filename = '%s'\n",
		      filename));
     return(NULL);      /* this is a directory, not a file */
     }
   else
     { size = stbuf.st_size;      /* length of file */
       if ((fp = fopen(filename, "r")) == NULL)
	 return(NULL);
       buffer = (MailBuffer *)
	 calloc(sizeof(MailBuffer), 
		sizeof(char));  /* create a Mail buffer object */
       /* initialize buffer contents to file contents */
       buffer->buffer = (char *) calloc(size + 2, sizeof(char));
       fread(buffer->buffer, sizeof(char), size, fp);
       *(buffer->buffer + size) = '\0';   /* terminate buffer string */
       fclose(fp);     /* close file */
       buffer->buflen = size + 2;
       buffer->bufindex = 0;
       buffer->column = 0;
       WBdebug(printf("<< Exiting: MBcreate_from_file(): successfully\n"));
       return(buffer);
     };
 };        /* end of MBcreate_from_file()  */

/****************************************************************/

void AlMB_destroy(buffer)
     MailBuffer *buffer;
  {
    free(buffer->buffer);
    free(buffer);

  };       /* end of AlMB_destroy()  */

/****************************************************************/

MailBuffer *AlMB_replace_buffer(buffer, new_buffer)
     MailBuffer *buffer;
     char *new_buffer;
  { /* -------------------------------------------------------------- */
    /* Replace the buffer string of "buffer" with a new buffer string */
    /* -------------------------------------------------------------- */

    /* First, free old buffer, if one existed. */
    if (buffer->buffer != NULL)
      free(buffer->buffer);

    /* Place new buffer and set instance variables to ready for reading */
    buffer->buffer = new_buffer;
    buffer->buflen = strlen(new_buffer) + 1;
    buffer->bufindex = 0;
    buffer->column = 0;

    return(buffer);

  };       /* end of AlMB_replace_buffer()  */

/****************************************************************/

/****************************************************************/

void AlMB_beginfield(buffer)
     MailBuffer *buffer;
  {
    if (buffer->column != 0)
      { if (buffer->buflen <= (buffer->bufindex + 10))
	  { /* Lengthen buffer size to hold new field */
	    buffer->buflen += 82;
	    buffer->buffer = (char *)
	      realloc(buffer->buffer,
		      (long) buffer->buflen);
	  };
	strcpy((buffer->buffer + buffer->bufindex), "\n");
	buffer->bufindex++;
	buffer->column = 0;
      };
  };       /* end of AlMB_beginfield()  */

/****************************************************************/

void AlMB_endfield(buffer)
     MailBuffer *buffer;
  {
    AlMB_beginfield(buffer); /* for now, these funcs take the same actions */
    buffer->buffer[buffer->bufindex] = '\0';  /* terminate the string */

  };       /* end of AlMB_endfield()  */

/****************************************************************/

int AlMB_getch(buffer)
     MailBuffer *buffer;
  { int ch;

    /* ----------------------------------------------------------*/
    /* Read a character from buffer and update buffer object.    */
    /* If the buffer isn't long enough, return -1 to flag error. */
    /* Otherwise, return the character (as an int).              */
    /* ----------------------------------------------------------*/

    if ((*(buffer->buffer + buffer->bufindex) != '\0') /* not end of string */
         && (buffer->buflen != buffer->bufindex))      /* not end of buffer */
      { /* get a character from the buffer object */
	ch = *(buffer->buffer + buffer->bufindex);
	buffer->bufindex++;
	return(ch);
      }
    else                     /* no character exist to get, clear buffer */
      { AlMB_clearbuf(buffer);
	return(-1);
      };
  };       /* end of AlMB_getch()  */

/****************************************************************/

int AlMB_peekch(buffer)
     MailBuffer *buffer;
  { int ch;

    /* ----------------------------------------------------------*/
    /* Peek at next character in buffer of buffer object.        */
    /* If the buffer isn't long enough, return -1 to flag error. */
    /* Otherwise, return the character (as an int).              */
    /* ----------------------------------------------------------*/

    if ((*(buffer->buffer + buffer->bufindex) != '\0') /* not end of string */
         && (buffer->buflen != buffer->bufindex))      /* not end of buffer */
      { /* peek at a character from the buffer object */
	ch = *(buffer->buffer + buffer->bufindex);
	return(ch);
      }
    else                     
      { /* no character exist to peek at in buffer */
	return(-1);
      };
  };       /* end of AlMB_peekch()  */

/****************************************************************/

void AlMB_clearbuf(buffer)
     MailBuffer *buffer;
 { /* clear the buffer */
   buffer->column = 0;
   buffer->bufindex = 0;
   *(buffer->buffer) = '\0';
 };

/****************************************************************/

char *AlMB_read_nchars(buffer, n)
     MailBuffer *buffer;
     unsigned int n;
  { int count;
    char *str;

    /* ---------------------------------------------------------*/
    /* Read a string up to the specified number of characters.  */
    /* If n is negative, or if the buffer isn't long enough,    */
    /*   then return NULL to flag an error.                     */
    /* Otherwise, return a copy of the string.                  */
    /* ---------------------------------------------------------*/

    if (n >= 0)
      {
	str = (char *) calloc((n + 1), sizeof(char)); 
        for (count = 0; count < n; count++)
	  str[count] = AlMB_getch(buffer);
	str[n] = '\0';
	return(str);
      }
    else if (n < 0)
      return(NULL);    /* Bad n was specified. */

  };       /* end of AlMB_read_nchars()  */

/****************************************************************/

char *AlMB_rdstring(buffer, delim)
     MailBuffer *buffer;
     char delim;
  { int n;

    /* --------------------------------------------------------*/
    /* Read a string up to the specified delimeter character.  */
    /* If no such delimeter is found, return NULL;             */
    /* Otherwise, return a copy of the string, and skip delim. */
    /* --------------------------------------------------------*/

    n = AlMB_index(buffer, delim);
    if (n < 0)
      return(NULL);
    else
      return(AlMB_read_nchars(buffer, n));

  };       /* end of AlMB_rdstring()  */

/****************************************************************/

int AlMB_index(buffer, delim)        /* returns -1 if not found */
     MailBuffer *buffer;
     char delim;
  { int i;
    char *bufptr;

    /* returns 0 based index to first occurance of delim char, or -1 */

    bufptr = buffer->buffer + buffer->bufindex;
    for (i = 0;
	 (*(bufptr + i) != delim)    /* found it */
	 && (buffer->bufindex + i
	     <= buffer->buflen)    /* exceeded buffer length */
	 && (*(bufptr + i) != '\0'); /* exceeded contents of buffer */
	 i++);

    if (*(bufptr + i) == delim)    /* found it */
      return(i);
    else
      return(-1);
  };             /* end of AlMB_index()  */

/****************************************************************/

int AlMB_rdinteger(buffer, intptr)  /* returns flag  1 if found, 0 otherwise */
     MailBuffer *buffer;
     int *intptr;         /* ptr to an int to place results in */
  { int i, result;
    int scale;

    WBdebug(printf(">> Entering: AlMB_rdinteger()\n"));

    i = AlMB_peekch(buffer);
    if (i == -1)
      { WBdebug(printf("<< Exiting: AlMB_rdinteger(): end-of-buffer.\n"));
	return(0);   /* end of buffer, failed */
      };

    /* Get the sign of the number */
    if (i == '-')
      { scale = -1;
	AlMB_getch(buffer);
	i = AlMB_peekch(buffer);
      }
    else
      scale = 1;

    /* read the first digit */
    if (i == -1)
      { WBdebug(printf("<< Exiting: AlMB_rdinteger(): end-of-buffer.\n"));
	return(0);                /* end of buffer, failed */
      }
    else if (!((i >= '0') && (i <= '9')))
      { WBdebug(printf("<< Exiting: AlMB_rdinteger(): non-number= '%c'\n", i));
	return(0);                /* non-number, failed */
      };

    /* read consecutive digits and form resulting integer */
    result = 0;
    while((i >= '0') && (i <= '9'))
      { AlMB_getch(buffer);   /* remove the character from the buffer */
	result = (result * 10) + i - '0';
	i = AlMB_peekch(buffer);
      };

    *intptr = scale * result;
    WBdebug(printf("<< Exiting: AlMB_rdinteger(): success, integer=%d.\n",
		   *intptr));
    return(1);                   /* successful */

  };             /* end of AlMB_rdinteger()  */

/****************************************************************/

void AlMB_prstring(buffer, str)
     MailBuffer *buffer;
     char *str;
  {
    int i;
    int len;

    len = strlen(str);

    /* Lengthen the buffer if needed. */
    if ((len + buffer->bufindex + 10) >= buffer->buflen)
      { buffer->buflen += (len + 80);
	buffer->buffer = (char *)
	  realloc(buffer->buffer,
		  (long) buffer->buflen);
      };

    if ((buffer->column + len) < 78)
      { strcpy((buffer->buffer) + buffer->bufindex, str);
	buffer->column += len;
	buffer->bufindex += len;
      }
    else if (len < 78)
      { /* Start a new line. */
	strcpy(buffer->buffer + buffer->bufindex, "\n ");
	buffer->bufindex += 2;
	buffer->column = 0;
	strcpy(buffer->buffer + buffer->bufindex, str);
	buffer->bufindex += len;
	buffer->column += len;
      }
    else
      { for (i = 0; i < len; i++)
	  { buffer->buffer[buffer->bufindex] = str[i];
	    buffer->bufindex++;
	    buffer->column++;
	    if (buffer->column >= 78)
	      { strcpy(buffer->buffer + buffer->bufindex, "\n ");
		buffer->bufindex += 2;
		buffer->column = 0;
	      };
	    if ((len - i + 10 + buffer->bufindex)
		>= buffer->buflen)
	      { buffer->buflen += (len - i + 80);
		buffer->buffer = (char *)
		  realloc((VOIDP) buffer->buffer,
			  (long) buffer->buflen);
	      };
	  };
      };
  };       /* end of AlMB_prstring()  */

/****************************************************************/

void AlMB_printeger(buffer, num)
     MailBuffer *buffer;
     int num;
  {
    int digits, n;
    char *str;
    
    n = num;

    /* Determine how many chars the num will consume as a string. */
    for(digits = 1; n >= 10; digits++)
      n /= 10;

    str = (char *) calloc((long) digits + 2, 1);
    sprintf(str, "%d%c", num, '\0');

    AlMB_prstring(buffer, str);
    free(str);

  };       /* end of AlMB_printeger()  */

/****************************************************************/

void AlMB_esc_prstring(buffer, str, delimeter)
     MailBuffer *buffer;
     char *str;
     char delimeter;
  {
    char *newstr;

    newstr = AlMB_encoded_string(str, delimeter);
    AlMB_prstring(buffer, newstr);
    free(newstr);

  };       /* end of AlMB_esc_prstring()  */

/****************************************************************/

char *AlMB_rdvalue_string(buffer)
     MailBuffer *buffer;
 { int done_flag;
   int i, newline_count, count, len;
   char *index, *str;

   /* ----------------------------------------------------------------- */
   /* Read the remainder of a mail field from the mail buffer.          */
   /* Return a copy. (This is probably used to retrieve a value field.) */
   /* ----------------------------------------------------------------- */

   WBdebug(printf(">> Entering: AlMB_rdvalue_string()\n"));

   /* Search buffer for end of the value string */
   /* ----------------------------------------- */
   done_flag = 0;
   newline_count = 0;
   index = buffer->buffer + buffer->bufindex;
   for (i = 0;
	(done_flag == 0) && (*index != '\0');
	i++)
     { 
       /* Value str is terminated by '\n' that is NOT followed by SP or '\t' */
       /* ------------------------------------------------------------------ */
       if ((*index == '\n') && (*(index + 1) != ' ')
           && (*(index + 1) != '\t'))
	 done_flag = 1;
       else if (*index == '\n')
	 newline_count++;
       index++;
     };
 
   str = (char *) calloc((i - newline_count + 2), sizeof(char)); 
   WBdebug(printf(" -- In: AlMB_rdvalue_string(): string =>\n"));
   len = 0;
   for (count = 0; count < i; count++)
     { if (AlMB_peekch(buffer) != '\n')
         { str[len++] = AlMB_getch(buffer);
	   WBdebug(printf("%c", str[count]));
	 }
       else                /* concat all lines of value field */
	 { AlMB_getch(buffer);
	   if ((AlMB_peekch(buffer) == ' ') OR (AlMB_peekch(buffer) == '\t'))
	     { AlMB_getch(buffer); /* ignore char after a new-line, too */
	       count++;
	     };
	 };
     };

   WBdebug(printf(
      "\n -- In: AlMB_rdvalue_string(): i = %d, count = %d, nl=%d\n",
		  i, count, newline_count));
   str[len] = '\0';
   WBdebug(printf("<< Exiting: AlMB_rdvalue_string(): len=%d, str='%s'\n",
		  strlen(str), str));
   return(str);

 };          /* end of AlMB_rdvalue_string()  */

/****************************************************************/

int AlMB_write_to_file(outfile, mailbuf)
     FILE *outfile;
     MailBuffer *mailbuf;
  {
    int len;

    if (outfile == NULL)
      return(FALSE);

    len = strlen(mailbuf->buffer);

    if (len > 0)
      { fprintf(outfile, "%s", mailbuf->buffer);

	/* insure a newline (and no blank line) */
	if (*((mailbuf->buffer) + len - 1) != '\n')
	  fprintf(outfile, "\n");
      };

    return(TRUE);

  };       /* end of AlMB_write_to_file()  */

/****************************************************************/
