Category : BBS Programs+Doors
Archive   : OREN113C.ZIP
Filename : O_RENUM.C
O_RENUM.C Does message renumbering for Opus 1.1x+ in "straight" C.
No fancy low-level calls, will probably be slower than Bob Hartman's
but will work on anything.
Fully released to the Opus community. Have fun, make it faster/better
just keep it free!
Doug Boone 119/5
P.O. Box 5108
Chico, CA 959528
Thanks to Bob Hartman for providing code. Although I didn't use any of
his code, being able to understand the logic and procedures he used
were extremely important.
---------------------------------------------------------------------
Pre-1.10 1/12/90 Steve Antonoff
Compiled with COMPACT model of TurboC
Added ECHO.CTL searching and command line
argument for SYSTEM directory
1.10.ix.A 1/22/90 Steve Antonoff
Applied Bob Davis' fix for 1.MSG 1/22/90 Steve Antonoff
added "adopted" and "thanks" lines
Added OPUS version number and COMPDATE
1.10.ix.C 1/31/90 Steve Antonoff:
Added additional checks to prevent killing of 1.msg in echo areas
Added -T (threshhold) option
Changed fgetc/fputc to fread/fwrite for LASTREAD file
1.10.ix.D 02/24/90 Steve Antonoff
Fixed error that occured if last message read was being deleted
Changed program name from RENUM to O_RENUM
1.10.ix.E 02/25/90 Steve Antonoff
Fixed renumbering to include last message (bug introduced in .ix.D)
1.10.ix.F 02/26/90 Steve Antonoff
Fixed processing for -N option to not require -R at the same time
1.10.ix.G 03/06/90 Steve Antonoff
Fixed processing for 1.MSG to update high water mark properly
1.10 3/13/90 Steve Antonoff
Reversed order for test on high water mark
Official release version for OPUS 1.10
1.10A 3/17/90 Steve Antonoff
Fixed update of LASTREAD to reflect correct value (was off by 1)
1.10B 3/19/90 Steve Antonoff
Added -W (write) and -A (automatic) options to write and read
renum parameters from RENUM.DAT in the OPUS SYSTEM path.
1.10C 3/19/90 Steve Antonoff
Fixed -N to count 1.MSG in the count of messages kept below #
1.10D 3/25/90 Steve Antonoff
Suppressed RENUMBER and RELINK if -R is not specified
1.10E 4/01/90 Steve Antonoff
-W only writes the parameters - doesn't do any renumbering
set exit() errorlevels to indicate error condition to DOS:
0 Successful or no renumber based on threshhold
1 Neither area number nor name given
2 Insufficient memory for message data
3 Error getting system info from SYSTEM.DAT
4 Write of RENUM parameters requested - no other processing performed
5 Can't find message path
6 Insufficient memory for user file data
7 Message number exceeds requeste max
8 Help (no arguments given)
1.10F 6/23/90 Steve Antonoff
"Neatened" up the status displays while running.
Added a display of the number of messages found.
Improved intelligence of command line parser to accept directory and
file names with or without an intervening space.
1.13 6/30/90 Steve Antonoff
Converted to "sparse" array manipulation, using qsort() to sort
message array. Thus, if an area has messages 1, 1000-1010, only 13
message slots will be used rather than 1011. Slot 0 is not used
ever.
Changed message number displays from %4d to %5d, allowing a full
32K-1 to be displayed properly.
1.13A 7/8/90 Steve Antonoff
Fixed bug in -M argument processing: 'M' was not listed in the switch
statement as a single parameter argument
1.13B 7/28/90 Steve Antonoff
Added -V (verbose) option and changed display of message numbers and
user names to default to off (quiet mode)
Added -Q (quiet) option to surpress normal status messages
Added -C (change directory) for future version
1.13C 7/31/90 Steve Antonoff
Changed test to allow -N option to allow -N=0,x
Fixed logic to use msg_count rather than max_msg in various places;
Use in_number and out_number rather than the index in various places
to accommodate sparse matrix
***************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include "otoolkit.h"
#include "compdate.h"
#define VERSION "1.13C"
#define MAX_USERS 24 /* Maximum # of users to update at once */
#define MAX_PATH 65 /* Maximum file path */
#define MAX_NAME 33 /* Maximum echo name */
#ifndef FALSE
#define FALSE 0
#define TRUE !FALSE
#endif
/*------------------------------------------------------------------------*/
/* Set of values to use with "flags" to tell renum what to do */
/*------------------------------------------------------------------------*/
#define KILL_DAYS 0x0001
#define KILL_NUMBER 0x0002
#define KILL_RCVD 0x0004
#define KILL_SENT 0x0008
#define RENUMBER 0x0010
#define RELINK_MSG 0x0020
#define IS_ECHO 0x1000
/*------------------------------------------------------------------------*/
/* Message status flags */
/*------------------------------------------------------------------------*/
#define ZAP 0x0001
#define EXISTS 0x0002
#define NOT_HERE 0x0000
/*------------------------------------------------------------------------*/
/* Return values */
/*------------------------------------------------------------------------*/
#define ERROR -1
#define SUCCESS 1
/*------------------------------------------------------------------------*/
/* Used to generate dates */
/*------------------------------------------------------------------------*/
#define YEAR_SHIFT 9
#define MONTH_SHIFT 5
#define DOS_EPOCH 80
/*------------------------------------------------------------------------*/
/* The basic internal structure to keep track of messages */
/*------------------------------------------------------------------------*/
struct a_msg
{
int status; /* internal renum status for this message */
int in_number; /* what was the original message number */
int out_number; /* what is the output number going to be */
int how_old; /* date_received date stamp */
int uplink; /* "there is a reply....." */
int downlink; /* "this is a reply to ......" */
int attr; /* the message's attribute */
};
/*------------------------------------------------------------------------*/
/* Global Data */
/*------------------------------------------------------------------------*/
struct a_msg *msg;
int MAX_MSGS = 1024; /* default max message area size */
char msg_path[MAX_PATH]; /* the message area path */
char echo_name[MAX_NAME]; /* the echo area name */
/*int flags = RELINK_MSG;*/ /* RENUM flags so we know what to do */
char *msg_file_format = "%s%i.MSG"; /* Format for message file name */
int months[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int area = -1; /* What area number is being used */
char echo_ctl_name[MAX_PATH],opus_sys_path[MAX_PATH];
int verbose = FALSE;
int quiet = FALSE;
int change_dir = FALSE;
struct flag_struct /* RENUM flags so we know what to do */
{
unsigned threshhold:1;
unsigned kill_days:1;
unsigned kill_number:1;
unsigned kill_rcvd:1;
unsigned kill_sent:1;
unsigned renumber:1;
unsigned relink:1;
unsigned is_echo:1;
unsigned spare:8;
};
struct renum_param /* RENUM parameter structure */
{
struct flag_struct flags;
int days;
int keep_lo,keep_hi;
int min_delete;
}renum,renum_from_file;
/*------------------------------------------------------------------------*/
/* Procedure definitions */
/*------------------------------------------------------------------------*/
void fix_lastread(int);
void fix_users(int,int);
int relink(int);
void delete_msgs(int);
int kill_count(int);
int message_count(int);
int get_sys_info(int,char *);
int get_msg_info(int *);
int msg_age_as_of(int);
void no_parms(int,int);
int scan_echo_ctl(char *, char *, char *);
int proc_args(int, char **);
void show_params(int);
int read_param_data(int,char *);
int write_param_data(int,char *);
int msg_cmp(struct a_msg *, struct a_msg *);
void xprintf(const char *);
void xprintf(const char *s)
{
if (!quiet)
printf("%s",s);
}
int msg_cmp(struct a_msg *msg1,struct a_msg *msg2)
{
return msg1->in_number - msg2->in_number;
}
int add_slash(char *path)
{
char last_char;
last_char = path[strlen(path)-1];
if (last_char != '\\' && last_char != ':')
strcat(path,"\\");
return last_char;
}
int main(int argc,char *argv[])
{
int i = 1;
int j;
int k;
#ifdef OLDVERSION
int days; /* Number of days for deleting */
int keep_lo;
int keep_hi;
int min_delete=-1;
#endif
int killed_count=0;
int write_data=0; /* 0 = no action, 1 = write data, 2 = read data*/
int older; /* Date stamp for older messages */
int max_msg; /* Highest message number found */
int msg_count; /* Number of messages found */
no_parms(argc-1,0); /* give instructions or credit */
msg_path[0] = 0; /* blast out msg_path */
echo_name[0] = 0;
echo_ctl_name[0] = 0;
opus_sys_path[0] = 0;
renum.min_delete = 0;
renum.flags.threshhold = FALSE;
renum.flags.kill_days = FALSE;
renum.flags.kill_number = FALSE;
renum.flags.kill_rcvd = FALSE;
renum.flags.kill_sent = FALSE;
renum.flags.renumber = FALSE;
renum.flags.relink = TRUE;
renum.flags.is_echo = FALSE;
write_data = proc_args(argc,argv);
if (!(msg_path[0]) && (area==-1))
{
printf("Neither message area directory nor area number given\n");
exit(1);
}
if ( NULL ==
(msg = (struct a_msg *) calloc(sizeof(struct a_msg),MAX_MSGS) ) )
{
printf("Unable to allocate space for %d messages\n",MAX_MSGS);
exit(2);
}
if (echo_ctl_name[0])
{
add_slash(echo_ctl_name);
strcat(echo_ctl_name,"ECHO.CTL");
}
if (opus_sys_path[0])
add_slash(opus_sys_path);
else
write_data = 0; /* can't read or write without OPUS system path */
if (msg_path[0])
{
strcpy(echo_name,msg_path);
add_slash(msg_path);
area = scan_echo_ctl(msg_path,echo_name,echo_ctl_name);
}
if (!(msg_path[0])) /* If the message path is no good..... */
{
if (ERROR == get_sys_info(area,opus_sys_path) )
exit(3);
}
if ((write_data & 2) && area > -1)
{
read_param_data(area,opus_sys_path);
proc_args(argc,argv);
}
show_params(write_data);
if ((write_data & 1) && area > -1)
{
write_param_data(area,opus_sys_path);
printf("Data written - O_RENUM terminating\n");
exit(4);
}
if (renum.flags.is_echo)
xprintf("Treating area as ECHOMAIL....\n");
i = strlen(msg_path) - 1;
if (msg_path[i] == '\\')
msg_path[i] = '\0';
if (access(msg_path,0))
{
printf("Can't find path %s\n\n",msg_path);
exit(5);
}
strcat(msg_path,"\\");
if (!quiet)
printf("Checking messages in %s\n",msg_path);
max_msg = get_msg_info(&msg_count);
if (!quiet)
{
printf("Max message number found found: %d\n",max_msg);
printf("Number of messages found: %d\n",msg_count-1);
printf("Sorting message array...\n");
}
qsort(msg,(size_t)msg_count,sizeof (struct a_msg),msg_cmp);
if (renum.flags.kill_sent)
{
xprintf("Marking messages that have been sent........\n");
for (i = 0; i<= msg_count; i++)
if (msg[i].attr & MSGSENT)
msg[i].status = ZAP;
}
if (renum.flags.kill_rcvd)
{
xprintf("Marking messages that have been received....\n");
for (i = 0; i<= msg_count; i++)
if (msg[i].attr & MSGREAD)
msg[i].status = ZAP;
}
if (renum.flags.kill_days)
{
xprintf("Marking old messages....\n");
older = msg_age_as_of(renum.days);
for (i = 1; i<= msg_count; i++)
if (msg[i].how_old < older)
msg[i].status = ZAP;
}
if (renum.flags.kill_number && !quiet)
printf(
"Marking messages after #%i and before the highest %i messages.....\n",
renum.keep_lo,renum.keep_hi);
else
{
renum.keep_hi = msg_count;
renum.keep_lo = 1;
}
if (renum.flags.kill_number)
{
j = renum.keep_hi;
i = msg_count;
while (j > 0 && i > renum.keep_lo)
{
if (EXISTS == msg[i].status)
j--;
i--;
}
if (renum.flags.is_echo) /* don't kill 1.msg for echos */
{
k = 2;
j = 1; /* but remember that we haven't! */
}
else
{
k = 1;
j = 0;
}
while (j < renum.keep_lo && k <= i)
{
if (EXISTS == msg[k].status)
j++;
k++;
}
for (j = k;j <= i;j++)
msg[j].status = ZAP;
}
killed_count = kill_count(msg_count);
if (renum.flags.threshhold && (killed_count < renum.min_delete) )
{
printf("Fewer than %i messages to delete (%i) - terminating\n",
renum.min_delete,killed_count);
exit(0);
}
if (!quiet)
printf("Killing %i messages....\n",killed_count);
delete_msgs(msg_count);
if (renum.flags.renumber)
{
max_msg = relink(msg_count);
fix_lastread(msg_count);
if (area != -1)
fix_users(msg_count,area);
}
exit(0);
return 0;
}
/*------------------------------------------------------------------------*/
/* Fix up LASTREAD in this area */
/*------------------------------------------------------------------------*/
void fix_lastread(int max)
{
char full[MAX_PATH];
FILE *infp;
int where;
int i;
int hit = FALSE;
sprintf(full,"%sLASTREAD",msg_path);
if (!quiet)
printf("Updating %s\n",full);
if ((infp = fopen(full,"r+b")) == NULL)
{
printf("Can't open %s\n",full);
return;
}
fread(&where,2,1,infp);
for (i = max; i >= 1 && !hit ; i--)
{
if (msg[i].in_number <= where)
{
where = msg[i].out_number;
hit = TRUE;
}
}
rewind(infp);
if (!hit)
where = 0;
fwrite(&where,2,1,infp);
fclose(infp);
return;
}
/*------------------------------------------------------------------------*/
/* Fix up user records, resetting message areas as needed */
/*------------------------------------------------------------------------*/
void fix_users(int high,int area)
{
struct _usr *auser;
int i;
int j;
int k;
int hit=FALSE;
int user_no = 0;
FILE *infp;
if ( (auser =
(struct _usr *)calloc(MAX_USERS, sizeof (struct _usr) ) ) ==
NULL)
{
printf("Unable to allocate memory for user file buffer\n");
exit(6);
}
if ((infp = fopen("USER.DAT","r+b")) == NULL)
{
printf("\nCouldn't find USER.DAT!!\n");
return;
}
xprintf("Updating USER records..........\n");
while ((k = fread(auser,sizeof(struct _usr),MAX_USERS,infp)) > 0)
{
for (i = 0; i < k; i++)
{
user_no++;
if (auser[i].lastmsg[area] > 0)
{
hit = FALSE;
for (j = high; j >= 1 && !hit; j--)
{
if (msg[j].in_number <= auser[i].lastmsg[area])
{
if (verbose && !quiet)
printf("\r%5d -> %5d: (%d) %-40.40s",
auser[i].lastmsg[area],msg[j].out_number,
user_no,auser[i].name);
auser[i].lastmsg[area] = msg[j].out_number;
hit = TRUE;
}
}
if (!hit)
auser[i].lastmsg[area] = 1;
}
}
fseek(infp,-((long) (k * sizeof(struct _usr))),SEEK_CUR);
fwrite(auser,sizeof(struct _usr),k,infp);
};
fclose(infp);
free(auser);
printf("\n");
return;
}
/*------------------------------------------------------------------------*/
/* Relink the replies in the message headers */
/*------------------------------------------------------------------------*/
int relink(int high)
{
int i,hit;
int j = 1;
int low = 1;
char new[MAX_PATH];
char old[MAX_PATH];
FILE *infp;
struct _msg amsg;
if (!quiet)
printf("Renumbering %sMessages........\n",
(renum.flags.relink) ?"& Relinking ":"");
if (renum.flags.is_echo)
{
low = 2;
j = 2;
}
/*------------------------------------------------------------------------*/
/* This is where renumbering really takes place, finding the messages */
/* that are still marked as EXISTS and crunching them down. */
/*------------------------------------------------------------------------*/
for (i = low; i <= high; i++)
{
if (EXISTS == msg[i].status)
{
msg[j].status = msg[i].status;
msg[j].in_number = msg[i].in_number;
msg[j].out_number = j;
msg[j].how_old = msg[i].how_old;
msg[j].uplink = msg[i].uplink;
msg[j].downlink = msg[i].downlink;
msg[j].attr = msg[i].attr;
j++;
}
}
/*------------------------------------------------------------------------*/
/* Now we've packed down the msg array and found the new highest message */
/* so begin the process of re-linking the replies */
/*------------------------------------------------------------------------*/
high = j;
if (high)
high--;
if (renum.flags.is_echo)
{
if (msg[1].status > 0)
msg[1].status = EXISTS;
if (msg[1].downlink > 0) /* Handle 1.MSG for echoes */
{
hit = FALSE;
for (j = high; j > 0 && !hit ;j--) /* High Water Mark */
{
if (msg[j].in_number <= msg[1].downlink)
{
msg[1].downlink = msg[j].out_number;
j = high;
hit = TRUE;
}
}
}
if (msg[1].uplink > 0)
{
hit = FALSE;
for (j = high; j > 0 && !hit; j--)
{
if (msg[j].in_number == msg[1].uplink)
{
msg[1].uplink = msg[j].out_number;
j = high;
hit = TRUE;
}
}
}
sprintf(new,"%s1.MSG",msg_path);
infp = fopen(new,"r+b");
fread(&amsg,sizeof(struct _msg),1,infp);
amsg.reply = msg[1].downlink;
amsg.up = msg[1].uplink;
fseek(infp,0L,SEEK_SET);
fwrite(&amsg,sizeof(struct _msg),1,infp);
fclose(infp);
} /* End of special handling for message #1 */
for (i = low; i <= high; i++)
{
if (msg[i].downlink > 0)
{
hit = FALSE;
for (j = low; j < i && !hit; j++)
{
if (msg[j].in_number == msg[i].downlink)
{
msg[i].downlink = j;
hit = TRUE;
}
}
}
if (msg[i].uplink > 0)
{
hit = FALSE;
for (j = i; j <= high && !hit; j++)
{
if (msg[j].in_number == msg[i].uplink)
{
msg[i].uplink = j;
hit = TRUE;
}
}
}
}
/*------------------------------------------------------------------------*/
/* Rename the messages */
/*------------------------------------------------------------------------*/
for (i = low; i <= high; i++)
{
if (msg[i].in_number != i)
{
sprintf(new,msg_file_format,msg_path,msg[i].out_number);
sprintf(old,msg_file_format,msg_path,msg[i].in_number);
if (verbose && !quiet)
printf("\r%5d -> %5d",msg[i].in_number,msg[i].out_number);
if (rename(old,new) != 0)
{
unlink(new);
rename(old,new);
}
if ( (msg[i].uplink || msg[i].downlink) && (renum.flags.relink) )
{
infp = fopen(new,"r+b");
fread(&amsg,sizeof(struct _msg),1,infp);
amsg.reply = msg[i].downlink;
amsg.up = msg[i].uplink;
fseek(infp,0L,SEEK_SET);
fwrite(&amsg,sizeof(struct _msg),1,infp);
fclose(infp);
}
}
}
if (verbose && !quiet)
printf("\n");
return(high); /* Return the new max_msg */
}
/*------------------------------------------------------------------------*/
/* Delete all the messages who have a status of ZAP */
/*------------------------------------------------------------------------*/
void delete_msgs(int high)
{
char full[MAX_PATH];
int i;
int j = 1;
if (renum.flags.is_echo)
j = 2;
for (i = j;i <= high;i++)
{
if (ZAP == msg[i].status)
{
if (verbose && !quiet)
printf("Kill %5d\r",msg[i].in_number);
sprintf(full,msg_file_format,msg_path,msg[i].in_number);
unlink(full);
}
}
if (verbose && !quiet)
printf("\n");
return;
}
/*------------------------------------------------------------------------*/
/* Read the SYSTEM*.DAT path, only works with Opus 1.10! */
/*------------------------------------------------------------------------*/
int get_sys_info(int area,char *opus_sys_path)
{
struct _sys one_sys;
FILE *handle;
char sys_path[MAX_PATH];
sprintf(sys_path,"%sSYSTEM%02X.DAT",opus_sys_path,area);
if ((handle = fopen(sys_path,"rb")) == NULL)
{
printf("Couldn't open %s!!\n",sys_path);
return(ERROR);
}
if ((fread(&one_sys,sizeof(struct _sys),1,handle)) < 0)
{
printf("Error reading %s!!\n",sys_path);
fclose(handle);
return(ERROR);
}
strcpy(msg_path,(char *)one_sys.msgpath);
fclose(handle);
if (one_sys.attrib & ECHOMAIL)
renum.flags.is_echo = TRUE;
return(SUCCESS);
}
/*------------------------------------------------------------------------*/
/* Read the message headers and load up the msg[] array */
/*------------------------------------------------------------------------*/
int get_msg_info(int *count)
{
struct _msg amsg;
char fullpath[MAX_PATH];
FILE *handle;
struct ffblk ffblk;
int done;
int i;
int high_msg = 0;
*count = 1;
sprintf(fullpath,"%s*.MSG",msg_path);
done = findfirst(fullpath,&ffblk,0);
printf("Checking:\n");
while (!done)
{
i = atoi(ffblk.ff_name);
if (i > MAX_MSGS)
{
printf("Message number %d exceeds max limit\n",i);
exit(7);
}
sprintf(fullpath,msg_file_format,msg_path,i);
if ((handle = fopen(fullpath,"rb")) == NULL)
msg[i].status = NOT_HERE;
else
{
if ((fread(&amsg,sizeof(struct _msg),1,handle)) < 0)
msg[i].status = ZAP; /* this must be a bogus message, no header */
else
{
if (verbose && !quiet)
printf("%5d\r",i);
msg[*count].status = EXISTS;
msg[*count].in_number = i;
msg[*count].uplink = amsg.up;
msg[*count].downlink = amsg.reply;
msg[*count].attr = amsg.attr;
msg[*count].how_old = amsg.date_arrived.date;
}
if (high_msg < i)
high_msg = i;
fclose(handle);
}
(*count)++;
done = findnext(&ffblk);
}
if (verbose && !quiet)
printf("\n");
return(high_msg);
}
/*------------------------------------------------------------------------*/
/* Work out what the date stamp would have been on the date (how_old) ago */
/*------------------------------------------------------------------------*/
int msg_age_as_of(int kill_date)
{
int day;
int month;
int year;
int check;
union REGS inregs,outregs;
inregs.h.ah = 0x2a;
intdos(&inregs,&outregs);
year = outregs.x.cx;
month = outregs.h.dh;
day = outregs.h.dl;
while (kill_date > 0)
{
if (day > kill_date)
{
day -= kill_date;
kill_date = 0;
}
else
{
months[1] = (year % 4 ? 28 : 29); /* Leap years through 2099 */
if (month == 1) /* move back to previous year */
{
if (kill_date >= 31)
kill_date -= 31;
else
{
day = 31 + day - kill_date;
kill_date = 0;
}
year--;
month = 12;
}
else
{
if (kill_date >= months[month-2])
kill_date -= months[month-2];
else
{
day = months[month-2] + day - kill_date;
kill_date = 0;
}
month--;
}
}
}
/*------------------------------------------------------------------------*/
if (!quiet)
printf("Kill older than: %02d-%02d-%4d\n",month,day,year);
/*------------------------------------------------------------------------*/
year = (year % 100);
year -= DOS_EPOCH;
check = year << YEAR_SHIFT;
check += month << MONTH_SHIFT;
check += day;
return(check);
}
/*------------------------------------------------------------------------*/
/* Your basic help and exit messages */
/*------------------------------------------------------------------------*/
void no_parms(int argc,int arg_char)
{
printf("\n\n"
"O_RENUM %s %s - adopted by Steve Antonoff, 133/302\n"
"Thanks to Bob Hartman, Doug Boone and Bob Davis.\n",
VERSION,COMPDATE);
if (argc > 0)
return;
if (argc < 0)
printf("\nError detected in command option: %c\n",arg_char);
printf(
"\n"
"Use as O_RENUM [-K] [-N #1 #2] [-D ##] [-S] [-M #] [-F] [-E path]\n"
" [-O path] [-T #] [-Q] [-V] [-R] [#|path|conf]\n"
"\n"
"-K .............. Kill received messages\n"
"-S .............. Delete messages that have already been sent\n"
"-N #1 #2 ........ Keep the first #1 messages and the last #2 messages\n"
"-D ## ........... Kill message more than ## days old\n"
"-M # ............ Maximum number of messages to handle (100-4500)\n"
"-F .............. Fast renum (don't relink message chains)\n"
"-E path ......... Path (disk:\\dir) to ECHO.CTL\n"
"-O path ......... Path (disk:\\dir) to OPUS SYSTEM??.DAT files\n"
"-T # ............ Threshhold (kill only if more than # msgs to kill)\n"
"-Q .............. Quiet mode (few displays)\n"
"-V .............. Verbose mode (message count & user names displayed)\n"
"-R .............. Renumber the messages\n"
"-W .............. Write parameters to RENUM.DAT and terminate\n"
"-A .............. Automatic renum (use data in RENUM.DAT\n"
"#/path/conf ..... Area number, path or conference name (tag) for messages\n"
"-W and -A require an area number, either from the command line or from\n"
"ECHO.CTL; both require an OPUS SYSTEM PATH (-o)\n"
"\n"
"Commands and parameters may be separated by spaces or they can be run\n"
"together, or they can be separated by \"=\" and the -N option can use a\n"
"comma to separte the two numbers.\n");
exit(8);
}
int scan_echo_ctl(char *msg_path,char *area_name,char *echo_ctl_path)
{
FILE *ctl;
int areanum;
char echo_path[MAX_PATH];
char echo_name[MAX_NAME];
char buffer[256];
if (!quiet)
printf("Scanning %s for echo area directory %s...\n",
echo_ctl_path,msg_path);
if ( ( ctl = fopen(echo_ctl_path,"rt") ) == NULL )
{
printf("%s not found.....\n",echo_ctl_path);
return -1;
}
while (!feof(ctl))
{
if (fgets(buffer,255,ctl))
{
sscanf(buffer,"%d %s %s",&areanum,echo_path,echo_name);
if ( !stricmp(echo_path,msg_path ) ||
!stricmp(echo_name,area_name) )
{
if (!quiet)
printf("Found: area #%d.....\n",areanum);
fclose(ctl);
msg_path[0] = 0;
return areanum;
}
}
}
printf("%s (%s) not found.....\n",msg_path,area_name);
return -1;
}
int kill_count(int msg_count)
{
int i,kill=0;
xprintf("Counting messages to be killed....\n");
if ( (renum.flags.is_echo) && msg[1].status == ZAP)
msg[1].status = EXISTS;
for (i=1 ; i <= msg_count ; i++)
if (msg[i].status == ZAP)
kill++;
return kill;
}
#ifdef UNNEEDED
int message_count(int max_msg)
{
int i,count=0;
xprintf("Counting messages found....\n");
for (i=1 ; i <= max_msg ; i++)
if (msg[i].status == EXISTS)
count++;
return count;
}
#endif
/**************************************************************************/
int proc_args(int argc, char *argv[])
{
int arg=1,write_data=0;
char *arg_s,*arg_data1,*arg_data2;
static int first=TRUE;
if (first)
{
printf("Processing command line arguments....\n");
}
while (arg
strupr(argv[arg]);
arg_s = argv[arg];
if (*arg_s == '-' || *arg_s == '/')
{
++arg_s;
arg_data1 = arg_s + 1;
if (*arg_data1 == '=')
arg_data1++;
arg_data2 = arg_data1;
while (*arg_data2 && *arg_data2 != ',')
arg_data2++;
if (*arg_data2 == ',' || *arg_data2 == '=')
arg_data2++;
switch (*arg_s) /* group options:
no parameters,
one parameter,
two parameters */
{
case 'K': /* no parameters */
case 'S':
case 'F':
case 'R':
case 'W':
case 'A':
case 'V':
case 'Q':
case 'C':
break;
case 'D': /* one parameter */
case 'T':
case 'E':
case 'O':
case 'M':
case 'N': /* two parameters */
if (!(*arg_data1) ) /* no parameters within arg */
{
arg++;
arg_data1 = argv[arg];
}
if (*arg_s == 'N') /* only two parameter option */
{
if (!(*arg_data2) ) /* no second parameter */
{
arg++;
arg_data2 = argv[arg];
}
}
break;
}
switch(*arg_s)
{
case 'V':
verbose = TRUE;
break;
case 'Q':
quiet = TRUE;
break;
case 'C':
change_dir = TRUE;
break;
case 'N':
renum.keep_lo = atoi(arg_data1);
renum.keep_hi = atoi(arg_data2);
renum.flags.kill_number = TRUE;
if (renum.keep_hi <= 0 || renum.keep_lo < 0)
no_parms(-1,*arg_s);
break;
case 'R':
renum.flags.renumber = TRUE;
break;
case 'D':
renum.days = atoi(arg_data1);
renum.flags.kill_days = TRUE;
if (renum.days <= 0)
no_parms(-1,*arg_s);
break;
case 'K':
renum.flags.kill_rcvd = TRUE;
break;
case 'S':
renum.flags.kill_sent = TRUE;
break;
case 'E':
if (first)
{
if (!(*arg_data1))
no_parms(-1,*arg_s);
strcpy(echo_ctl_name,arg_data1);
}
break;
case 'O':
if (first)
{
if (!(*arg_data1))
no_parms(-1,*arg_s);
strcpy(opus_sys_path,arg_data1);
}
break;
case 'M':
MAX_MSGS = atoi(arg_data1);
if (MAX_MSGS == 0)
no_parms(-1,*arg_s);
if (MAX_MSGS < 100)
MAX_MSGS = 100;
if (MAX_MSGS > 4500)
MAX_MSGS = 4500;
break;
case 'T':
renum.min_delete = atoi(arg_data1);
if (renum.min_delete <= 0)
no_parms(-1,*arg_s);
renum.flags.threshhold = TRUE;
break;
case 'F':
renum.flags.relink = FALSE;
break;
case 'W':
write_data += 1;
break;
case 'A':
write_data += 2;
break;
}
}
else
{
if (first)
{
if (isdigit(*argv[arg]) > 0) /* is this an area number? */
area = atoi(argv[arg]);
else
strcpy(msg_path,argv[arg]); /* must be just a path */
}
}
arg++;
}
first = FALSE;
return (write_data);
}
/**************************************************************************/
void show_params(int write_data)
{
char *on="ON",*off="OFF";
if (quiet)
return;
printf("\nWriting parameters: %s",write_data==1?on:off);
printf("\nReading parameters: %s",write_data==2?on:off);
printf("\nThreshhold: %s",renum.flags.threshhold?on:off);
if (renum.flags.threshhold)
printf(" %d messages minimum",renum.min_delete);
printf("\nDelete by days: %s",renum.flags.kill_days?on:off);
if (renum.flags.kill_days)
printf(" %d days old or older",renum.days);
printf("\nKill by Msg Number: %s",renum.flags.kill_number?on:off);
if (renum.flags.kill_number)
printf(" Leave first %d and last %d messages",
renum.keep_lo,renum.keep_hi);
printf("\nRelinking: %s",renum.flags.relink?on:off);
printf("\nRenumbering: %s",renum.flags.renumber?on:off);
printf("\nKill Sent: %s",renum.flags.kill_sent?on:off);
printf("\nKill Rcvd: %s",renum.flags.kill_rcvd?on:off);
if (*opus_sys_path)
printf("\nOPUS System Path: %s",opus_sys_path);
if (*echo_ctl_name)
printf("\nECHO.CTL Name: %s",echo_ctl_name);
printf("\nMessage path: %s",msg_path);
printf("\n");
}
int read_param_data(int area,char *opus_sys_path)
{
FILE *handle;
char sys_path[MAX_PATH];
sprintf(sys_path,"%sRENUM.DAT",opus_sys_path);
if ((handle = fopen(sys_path,"rb")) == NULL)
{
printf("Couldn't open %s!!\n",sys_path);
return(ERROR);
}
fseek(handle,(long)area * sizeof(struct renum_param),SEEK_SET);
if ((fread(&renum_from_file,sizeof(struct renum_param),1,handle)) < 0)
{
printf("Error reading %s!!\n",sys_path);
fclose(handle);
return(ERROR);
}
memcpy(&renum,&renum_from_file,sizeof(struct renum_param));
fclose(handle);
return(SUCCESS);
}
int write_param_data(int area,char *opus_sys_path)
{
FILE *handle;
char sys_path[MAX_PATH];
int area_no;
sprintf(sys_path,"%sRENUM.DAT",opus_sys_path);
if (access(sys_path,0))
{
if ( (handle = fopen(sys_path,"w+b") ) == NULL)
{
printf("Couldn't create %s!!\n",sys_path);
return (ERROR);
}
for (area_no = 0 ; area_no < 256 ; area_no++)
{
if ((fwrite(&renum,sizeof(struct renum_param),1,handle)) < 0)
{
printf("Error initializing %s!!\n",sys_path);
return(ERROR);
}
}
fclose(handle);
}
if ( ( handle = fopen(sys_path,"r+b") ) == NULL)
{
printf("Couldn't open %s!!\n",sys_path);
return(ERROR);
}
fseek(handle,(long)area * sizeof(struct renum_param),SEEK_SET);
if ((fwrite(&renum,sizeof(struct renum_param),1,handle)) < 0)
{
printf("Error writing %s!!\n",sys_path);
fclose(handle);
return(ERROR);
}
fclose(handle);
return(SUCCESS);
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/