/* MSG2TXT.C
 *------------------------------------------------------------------------
 *
 *  Program to convert a RBBS Messages file to text format
 *
 *   Tom Collins
 *   09-15-90
 */

#pragma pack(1)

typedef unsigned int Bit;
typedef unsigned int uint;

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <io.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <dos.h>
#include "rbbs.h"

#define  TRUE     1
#define  FALSE    0

#define  VERSION "v0.05"

#define  RBBS_EOL '\xE3'
#define  DELETED_MESSAGE '\xE2'

char     *trim_string(char * );
void     txt_printf(int ,char *,... );
void     *read_rec(uint );
void     twirl(void );
char     *unpath(char * );
void     center_txt_puts(char * );

int  fhin;
FILE *fpout;
int  lines_printed;
int  use_page_feeds;

void main(int argc ,char *argv[] )
{
   uint   first_rec, next_avail_rec;
   uint   current_rec;
   uint   recs_in_msg;
   uint   message_number, starting_message_number;
   int    anything_exported;
   int    no_privates;
   int    i;
   char   *filename, *p;
   char   temp[80];
   struct rbbs_checkpoint     *chkpt;
   struct rbbs_message_header *hdr;
   struct dosdate_t ddate;
   struct dostime_t dtime;

   if (argc < 3 )
      {
      printf("Usage: MSG2TXT Messages_File_Name Text_File_Name [Start] [/NOPAGE] [/NOPRIVATE]\n\n" );
      printf("       Messages_File_Name    = Name of your RBBS messages file\n" );
      printf("       Text_File_Name        = Name of the file to write the text to\n" );
      printf("       Start (Optional)      = Start exporting at what message number\n" );
      printf("       /NOPAGE (Optional)    = Don't put page feeds in the output file\n" );
      printf("       /NOPRIVATE (Optional) = Don't export private messages\n" );
      exit(1 );
      }
   printf("MSG2TXT %s - Super Dooper RBBS Message to Text Converter, by Tom Collins\n\n" ,VERSION );

   printf("Converting: %s => %s... " ,strupr(argv[1] ) ,strupr(argv[2] ) );

   starting_message_number = 0;
   use_page_feeds          = TRUE;
   no_privates             = FALSE;
   anything_exported       = FALSE;

   if (argc > 3 )
      {
      starting_message_number = atoi(argv[3] );
      for (i = 3; i < argc; i++)
	 {
         strupr(argv[i] );
         if (strcmp(argv[i] ,"/NOPAGE" ) == 0 )
	    {
	    use_page_feeds = FALSE;
	    }
         if (strcmp(argv[i] ,"/NOPRIVATE" ) == 0 )
	    {
	    no_privates = TRUE;
	    }
	 }
      }

   fhin = open(argv[1] ,O_RDONLY|O_BINARY );
   if (fhin < 0 )
      {
      printf("Error Opening Messages File %s - Program Aborted\n" ,argv[1] );
      exit(1 );
      }

   fpout = fopen(argv[2] ,"wt" );
   if (fpout == NULL )
      {
      printf("Error Opening Text File %s - Program Aborted\n" ,argv[2] );
      exit(1 );
      }

   chkpt = read_rec(0 );

   first_rec      = atoi(chkpt->first_message );
   next_avail_rec = atoi(chkpt->next_message );

   lines_printed = 0;
   if (use_page_feeds )
      {
      txt_printf(0 ,"\f" );
      }

   filename = unpath(argv[1] );
   if ((p = strstr(filename ,"M.DEF" ) ) != NULL )
      {
      *p = '\0';
      }
   else if ((p = strchr(filename ,'.' ) ) != NULL )
      {
      *p = '\0';
      }

   txt_printf(1 ,"" );
   center_txt_puts("----------------------------------------" );

   sprintf(temp ,"%s Conference Messages" ,filename );
   center_txt_puts(temp );

   _dos_getdate(&ddate );
   _dos_gettime(&dtime );
   sprintf(temp ,"Converted: %02u-%02u-%4u %02u:%02u:%02u" ,
              ddate.month ,
              ddate.day ,
              ddate.year ,
              dtime.hour ,
              dtime.minute ,
              dtime.second );

   center_txt_puts(temp );

   sprintf(temp ,"Created by MSG2TXT %s, by Tom Collins" ,VERSION );
   center_txt_puts(temp );
   center_txt_puts("----------------------------------------" );

   txt_printf(2 ,"" );

   current_rec = first_rec - 1;
   while (current_rec < next_avail_rec )
      {
      hdr = read_rec(current_rec );
      recs_in_msg = atoi(hdr->message_rec );
      if (recs_in_msg <= 0 )
         {
         recs_in_msg = 1;
         }
      message_number = atoi(hdr->mess_number );

      if (message_number < starting_message_number  ||
	  (hdr->read_only == '*' && no_privates )   ||
	  hdr->active_indicator == DELETED_MESSAGE )
         {
	 current_rec += recs_in_msg;
         }
      else
         {
	 uint j, txt_size;
         char *p, *one_line, *full_txt;

	 txt_printf(1 ," Msg #: %4.4s" ,&(hdr->read_only ) );
         txt_printf(1 ,"  From:  %31.31s Sent: %8.8s %5.5s" ,hdr->message_from ,hdr->message_date_sent ,hdr->message_time );
         txt_printf(1 ,"    To:  %22.22s          Rcvd: -NO-" ,hdr->message_to );
	 txt_printf(2 ,"  Subj:  %25.25s" ,hdr->message_subject );

         current_rec++;
	 txt_size = (recs_in_msg - 1 ) << 7;

	 full_txt = malloc(txt_size + 1 );
         if (full_txt == NULL )
            {
            printf("\nMemory Allocation Error... Program Aborted.\n" );
	    exit(1 );
            }

	 for (j = 0; j < recs_in_msg-1; j++)
            {
	    p = read_rec(current_rec++ );
	    memcpy(&full_txt[j << 7] ,p ,128 );
            }
	 full_txt[txt_size] = '\0';

         one_line = full_txt;
         for (j = 0; j < txt_size; j++ )
            {
            if (full_txt[j] == RBBS_EOL )
               {
               full_txt[j] = '\0';
               trim_string(one_line );
               if (one_line[0] != 0x01 && strncmp(one_line ,"SEEN-BY" ,7 ) != 0 )
                  {
                  txt_printf(1 ,"%s" ,one_line );
                  }
               one_line = &full_txt[j + 1];
               }
            }

         txt_printf(1 ,"" );
         free(full_txt );

	 anything_exported = TRUE;
	 }

      twirl();
      }

   if (!anything_exported )
      {
      txt_printf(1 ,"No New Messages Found..." );
      }

   printf("Done.\n");

   fclose(fpout );
   close(fhin );

   exit(0);
}

/*  TRIM_STRING
 *----------------------------------------------------------------------------
 *
 *  Removes trailing spaces and '\n's
 *  from a string.
 *
 *  Globals Used:
 *     <none>
 *
 *  Returns:
 *     The trimmed string
 */
char  *trim_string(char *s )
{
   int i;
   for (i = strlen(s)-1; i >= 0; i--)
      if (s[i] == ' ' || s[i] == '\n' || s[i] == '\r' )
         s[i] = '\0';
      else
         break;

   return(s );
}

/*  READ_REC
 *----------------------------------------------------------------------------
 *
 *  Reads an RBBS record, and returns a pointer to it
 *
 */
#define READ_BUFFER_SIZE (unsigned) 32512

void  *read_rec(uint rec_num )
{
   static char *buf = NULL;
   static uint low_rec_in_ram = -1;
   static uint high_rec_in_ram = -1;

   if (buf == NULL )
      {
      buf = malloc(READ_BUFFER_SIZE );
      if (buf == NULL )
         {
         printf("\nMemory Allocation Error... Program Aborted.\n" );
	 exit(1 );
         }
      }

   /*
    * See if we need to read from disk
    */
   if (rec_num < low_rec_in_ram || rec_num > high_rec_in_ram )
      {
      int stat;
      long m;
      long l, bytes_to_read;

      l = ((long ) rec_num) << 7L;           /* rec_num << 7 */
      m = lseek(fhin ,l ,SEEK_SET );
      bytes_to_read = filelength(fhin ) - l;
      if (bytes_to_read > READ_BUFFER_SIZE )
         {
         bytes_to_read = READ_BUFFER_SIZE;
         }
      stat = read(fhin ,buf ,(unsigned) bytes_to_read );
      low_rec_in_ram = rec_num;
      high_rec_in_ram = rec_num + (uint) (bytes_to_read >> 7 ) - 1;
      }

   return (buf + ((rec_num - low_rec_in_ram) << 7 ) );
}

/*  TXT_PRINTF
 *----------------------------------------------------------------------------
 *
 *  Prints a string to the text output file
 *
 */
void txt_printf(int returns ,char *p ,... )
{
   int i;
   va_list arg_ptr;
   static char *buf = NULL;

   if (buf == NULL )
      {
      buf = malloc(8192 );
      if (buf == NULL )
         {
         printf("\nMemory Allocation Error... Program Aborted.\n" );
	 exit(1 );
         }
      }
   /*
    *  Process input string and optional parameters
    */
   va_start(arg_ptr ,p );
   i = vsprintf(buf ,p ,arg_ptr );

   fputs(buf ,fpout );
   for (i = 0; i < returns; i++)
      {
      fputs("\n" ,fpout );
      lines_printed++;
      if (lines_printed == 60 && use_page_feeds )
         {
         fputs("\f\n\n\n" ,fpout );
         lines_printed = 0;
         }
      }
}

/*  TWIRL
 *---------------------------------------------------------------------------
 *
 *  Prints a twirling clock on the screen
 *
 */
void twirl(void )
{
   static int i = 0, j = 0;
   static char *t = "/-\\|/-\\|";

   if ((j++ % 5 ) == 0 )
      {
      putchar(t[i++] );
      putchar('\b' );

      if (t[i] == '\0' )
	 i = 0;
      }
}

/*  UNPATH
 *----------------------------------------------------------------------------
 *
 *  Removes the path from a filename, and returns a pointer to it.
 *
 */
char  *unpath(char *pathname )
{
   int  i;

   i = strlen(pathname );
   if (i != 0 )
      {
      for ( ; i > 0; i-- )
         {
         if (pathname[i] == '\\' || pathname[i] == ':' )
            {
            i++;
            break;
            }
         }
      }
   return(&pathname[i] );
}

/*  CENTER_TXT_PUTS
 *----------------------------------------------------------------------------
 *
 *  Writes a string to the text output file, centered on the line
 *
 */
void center_txt_puts(char *s )
{
   int i;

   for (i = 0; i < (80 - strlen(s ) ) / 2; i++ )
      {
      txt_printf(0 ," " );
      }
   txt_printf(1 ,s );
}
