home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 2 BBS
/
02-BBS.zip
/
MAXTOP.LZH
/
MAXTOP.C
< prev
next >
Wrap
Text File
|
1991-01-13
|
26KB
|
707 lines
/***************************************************************************
* *
* MaxTop Source Code, Version 1.00 *
* Copyright 1991 by Douglas J. Hill. All rights reserved. *
* COMMERCIAL DISTRIBUTION AND/OR USE PROHIBITED WITHOUT *
* WRITTEN CONSENT FROM THE AUTHOR. *
* *
* MaxTop is a small external utility for Maximus BBS (OS/2 version). *
* After each caller logs off the system, MaxTop will compile a list of *
* the top five uploaders and top five downloaders. *
* *
* Note: This program is functional but not particularly elegant. There *
* are many places for improvement which I will get around to *
* at some point. *
* *
* In writing this program I have used the works of several others. Most *
* notably Peter Fitzsimmons for his COMM.DLL routines and Scott Dudley *
* for his source to Maximus BBS (and the legal mumbo jumbo that follows).*
* *
* Non-commercial distribution and/or use is permitted under *
* the following terms: *
* 1) You may copy and distribute verbatim copies of the *
* MaxTop source, documentation, and executable code as you *
* receive it, in any medium, provided that you *
* conspicuously and appropriately publish on each copy a *
* valid copyright notice "Copyright 1991 by Douglas *
* J. Hill"; keep intact the notices on all files that *
* refer to this Licence Agreement and to the absence of *
* any warranty; PROVIDE UNMODIFIED COPIES OF THE *
* DOCUMENTATION AS PROVIDED WITH THE PROGRAM; and give *
* any other recipients of the MaxTop program a copyof this *
* Licence Agreement along with the program. *
* Under no circumstances is MaxTop to be *
* distributed in such a way as to be construed as "value *
* added" in a sales transaction, such as, but not limited *
* to, software bundled with a modem or CD-ROM software *
* collections, without the prior written consent of the *
* author. *
* *
* 2) Mere aggregation of another unrelated program with this *
* program and documentation (or derivative works) on a *
* volume of a storage or distribution medium does not *
* bring the other program under the scope of these terms. *
* *
* NO WARRANTY *
* *
* *
* BECAUSE MAXTOP IS LICENSED FREE OF CHARGE, WE PROVIDE *
* ABSOLUTELY NO WARRANTY. EXCEPT WHEN OTHERWISE STATED IN *
* WRITING, DOUGLAS HILL AND/OR OTHER PARTIES PROVIDE MAXTOP *
* "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED *
* OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR *
* PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE *
* OF MAXTOP, AND THE ACCURACY OF ITS ASSOCIATED *
* DOCUMENTATION, IS WITH YOU. SHOULD MAXTOP OR ITS *
* ASSOCIATED DOCUMENTATION PROVE DEFECTIVE, YOU ASSUME THE *
* COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. *
* *
* IN NO EVENT WILL DOUGLAS HILL BE RESPONSIBLE IN ANY WAY FOR *
* THE BEHAVIOR OF MODIFIED VERSIONS OF MAXTOP. IN NO *
* EVENT WILL DOUGLAS HILL AND/OR ANY OTHER PARTY WHO MAY *
* MODIFY AND REDISTRIBUTE MAXTOP AS PERMITTED ABOVE, BE *
* LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST *
* MONIES, OR OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL *
* DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE *
* (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING *
* RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR *
* A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) *
* MAXTOP, EVEN IF DOUGLAS HILL HAS BEEN ADVISED OF THE *
* POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER *
* PARTY. *
* *
* The author can be contacted at any one of the addresses below: *
* *
* Douglas J. Hill InterNet djhill@rodan.acs.syr.edu *
* Box 4266 BitNet rtron@SUVM *
* Rockville, MD 20850 BBS (301) 718-4690 - 2400, 24 Hours *
* *
* ----------------------------------------------------------------------- *
* *
* The COMM.DLL and COMM.H are Copyright (C) 1990 A:WARE Inc. *
* *
***************************************************************************/
/***************************************************************************
* Flag Date Programmer Description of change
*--------------------------------------------------------------------------
* (none) 01/12/91 Douglas J. Hill Original code
***************************************************************************/
#include <io.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <process.h> /* exit() prototype */
#include <stdlib.h> /* atoi() prototype */
#ifndef APIENTRY /* if APIENTRY isn't defined, we most likely */
#include <os2def.h> /* haven't got the rest of the OS/2 types so */
typedef SHANDLE HFILE; /* include them now. */
#endif
#include "max_u.h" /* maximus user file record (part of MAX source) */
#include "comm.h" /* part of COMM package from A:WARE (see above) */
#include "proto.h" /* functional prototypes */
#include "maxtop.h" /* constants, macros, etc. */
#include "global.c" /* global variables */
int main(argc, argv, envp)
int argc;
char *argv[];
char *envp[];
{
int userfile; /* USER.BBS file pointer */
int record_length; /* length of each user record in USER.BBS file */
struct _usr user; /* structure to hold one user from USER.BBS */
int i;
char out[100], /* buffers used to display output. */
temp[20];
/*
* first print out banner and parse any arguments on the command line
*/
Banner();
if (ParseArgs(argc,argv))
{
sprintf(msg,"\n\nUnknown argument.\n\n");
Output(msg);
Terminate(1);
}
/*
* if we're not local then we need to get the com port handle and turn the
* watch dog facility on.
*/
if (!local)
{
ComHRegister(hComm, &hCommPort, (USHORT) 0, (USHORT) 0);
ComWatchDog(hCommPort,TRUE,(USHORT)1);
}
/*
* open and read in MAXTOP.CTL. Parse any tokens contained inside. If
* there are any errors we quit the whole app.
*/
if (!ReadCTLFile())
Terminate(1);
/*
* add the file names to the paths supplied in the .CTL file. Note that
* we don't add any backslashes here so they must be in the .CTL file.
*/
strcat(userBBSpath,"USER.BBS");
strcat(maxtoppath,"MAXTOP.DAT");
/*
* read in the data from disk if it exists. If it doesn't, simply
* initialize the structures.
*/
ReadTopLists();
/*
* if we're not in display mode or we don't have any data yet then try and
* read the USER.BBS file and get some.
*/
if ((!display) || (newfile))
{
InitLists();
/*
* open the USER.BBS file in READ ONLY mode. We also use BINARY so that
* we don't translate CRLFs to LFs
*/
if ((userfile=open(userBBSpath, O_RDONLY | O_BINARY))==-1)
{
sprintf(msg,"Can't find file %s\n",userBBSpath);
Output(msg);
Terminate(2);
}
/*
* read in the first record to determine record size. Note that this
* causes us not to check the first user's upload/download stats. This
* is OK since it's most likely the sysop and who cares what he's done.
*/
read(userfile,&user,sizeof(struct _usr));
record_length = user.struct_len ? (user.struct_len * 20) : 180;
/*
* read each user from USER.BBS until EOF. For each user, see if his
* stats beat any of the users in either the upload or download lists.
* If so, call the appropriate function to add him in.
*/
while (!eof(userfile)) {
read(userfile,&user,sizeof(struct _usr));
if (debug)
{
sprintf(msg,"Read user %s\n",user.name);
Output(msg);
}
if ((i=CheckTopDownloader(&user)))
AddTopDownloader(&user,i);
if ((i=CheckTopUploader(&user)))
AddTopUploader(&user,i);
}
/*
* All done reading. Close the user file and write the lists out to
* disk.
*/
close(userfile);
WriteTopLists();
}
/*
* if we've been asked to display the data then printf it all out to the
* console or modem (or both).
*/
if (display)
{
sprintf(msg,"\n%s\n\n",title); Output(msg);
sprintf(msg,"Downloaders Uploaders\n");
Output(msg);
sprintf(msg,"-------------------------------------------------\n");
Output(msg);
for (i=0; i<MAX_ENTRIES ;i++ ) {
strcpy(out,TopDownloaders[i].name);
strncat(out,DOTS,31-strlen(TopDownloaders[i].name));
sprintf(temp,"%dk",TopDownloaders[i].amount);
sprintf(msg,"%s%7s ",out,temp); Output(msg);
strcpy(out,TopUploaders[i].name);
strncat(out,DOTS,31-strlen(TopUploaders[i].name));
sprintf(temp,"%dk",TopUploaders[i].amount);
sprintf(msg,"%s%7s\n",out,temp); Output(msg);
}
strcpy(msg,"\n\n"); Output(msg);
/*
* we've now sent all the data but most likely there's some still waiting
* to be sent (especially at 1200 and 2400 baud) so let's wait until
* the queue empties before proceeding.
*/
if (!local)
ComTxWait(hCommPort,-1L);
}
/*
* now that all the data's been sent, turn off the watch dog and close
* out com port.
*/
if (!local)
{
ComWatchDog(hCommPort,FALSE,(USHORT)0);
ComClose(hCommPort);
}
return 0;
}
/******************************************************************************
* Function: ReadTopLists()
*
* Purpose: This function reads the top download/upload data from disk into
* global variables. If the file can't be opened, the function
* initializes the sturctures to zeros.
*
*****************************************************************************/
void ReadTopLists(void)
{
if ((toplistsfile=open(maxtoppath, O_RDONLY | O_BINARY))==-1)
{
/*
* can't open the top lists so just initialize the structures
*/
newfile=TRUE;
InitLists();
}
else
{
read(toplistsfile,&TopDownloaders,sizeof(TopDownloaders));
read(toplistsfile,&TopUploaders,sizeof(TopUploaders));
close(toplistsfile);
}
}
/*****************************************************************************
* Function: WriteTopLists()
*
* Purpose: This function opens the MaxTop data file (MAXTOP.DAT) for
* writing and places the download/upload lists on disk closing
* the file when done. If the file doesn't exist, this function
* will call creat() to create the file.
*****************************************************************************/
void WriteTopLists(void)
{
if ((toplistsfile=open(maxtoppath,O_RDWR | O_BINARY))== -1)
{
if ((toplistsfile=creat(maxtoppath,S_IWRITE))==-1)
{
sprintf(msg, "Couldn't create %s\n",maxtoppath); Output(msg);
Terminate(1);
}
}
write(toplistsfile,&TopDownloaders,sizeof(TopDownloaders));
write(toplistsfile,&TopUploaders,sizeof(TopUploaders));
close(toplistsfile);
}
/****************************************************************************
* Function: CheckTopDownloader()
*
* Purpose: This function is called by the main routine to see if the
* current user belongs on the top download list. The function
* scans all of the existing entries in the list to see if the
* current user has downloaded more than any of them. If so,
* this function returns the index which the current user should
* occupy. AddTopDownloader() will take care of inserting the
* user into the list.
*****************************************************************************/
int CheckTopDownloader(user)
struct _usr *user;
{
int i;
for (i=0; i<MAX_ENTRIES ; i++ ) {
if (user->dnld > TopDownloaders[i].amount)
{
/*
* before we add the user to the list, make sure he's not already
* in the list as the previous entry.
*/
if ((i!=0) && (strcmp(TopDownloaders[i-1].name,user->name)))
return i+1;
else if (i==0)
return 1;
else
return 0;
}
}
return 0;
}
/****************************************************************************
* Function: CheckTopUploader()
*
* Purpose: This function is called by the main routine to see if the
* current user belongs on the top upload list. The function
* scans all of the existing entries in the list to see if the
* current user has uploaded more than any of them. If so,
* this function returns the index which the current user should
* occupy. AddTopUploader() will take care of inserting the
* user into the list.
*****************************************************************************/
int CheckTopUploader(user)
struct _usr *user;
{
int i;
for (i=0; i<MAX_ENTRIES ; i++ ) {
if (user->upld > TopUploaders[i].amount)
{
/*
* before we add the user to the list, make sure he's not already
* in the list as the previous entry.
*/
if ((i!=0) && (strcmp(TopUploaders[i-1].name,user->name)))
return i+1;
else if (i==0)
return 1;
else
return 0;
}
}
return 0;
}
/****************************************************************************
* Function: AddTopDownloader()
*
* Purpose: This function adds the current user into the top download list
* at element i. All elements in the list are shuffled down to
* make room for the new user with the last element falling off
* the list.
****************************************************************************/
void AddTopDownloader(user,i)
struct _usr *user;
int i;
{
int j;
if (i==MAX_ENTRIES)
{
strcpy(TopDownloaders[i-1].name,user->name);
TopDownloaders[i-1].amount = user->dnld;
}
else
{
for (j=MAX_ENTRIES-2; j>i-2 ; j-- ) {
TopDownloaders[j+1]=TopDownloaders[j];
}
strcpy(TopDownloaders[i-1].name,user->name);
TopDownloaders[i-1].amount = user->dnld;
}
}
/****************************************************************************
* Function: AddTopUploader()
*
* Purpose: This function adds the current user into the top upload list
* at element i. All elements in the list are shuffled up to
* make room for the new user with the last element falling off
* the list.
****************************************************************************/
void AddTopUploader(user,i)
struct _usr *user;
int i;
{
int j;
if (i==MAX_ENTRIES)
{
strcpy(TopUploaders[i-1].name,user->name);
TopUploaders[i-1].amount = user->upld;
}
else
{
for (j=MAX_ENTRIES-2; j>i-2 ; j-- ) {
TopUploaders[j+1]=TopUploaders[j];
}
strcpy(TopUploaders[i-1].name,user->name);
TopUploaders[i-1].amount = user->upld;
}
}
/****************************************************************************
* Function: ReadCTLFile()
*
* Purpose: This function opens the MaxTop control file (MAXTOP.CTL) and
* reads each line looking for tokens. Any line that starts
* with a % is considered a comment and is ignored.
* Any other character in postition 1 of a line is considered
* to be the start of a token. The text from this character
* to the next space character are sent for parsing. For
* example if a line were:
*
* ThisIsAToken FOO FOO2 BLAH BLAH BLAH BLAH BLAH BLAH BLAH
*
* the word 'ThisIsAToken' would be sent to ParseToken().
* The rest of the line would be considered as data for that
* token.
* Blank lines are also ignored.
****************************************************************************/
int ReadCTLFile(void)
{
int ctlfile;
int i;
char ch;
char token[40];
bit firstchar=TRUE;
if (debug)
{
sprintf(msg,"\nReading control file...\n"); Output(msg);
}
if ((ctlfile=open("MAXTOP.CTL",O_RDONLY | O_BINARY))==-1)
{
printf("Unable to open MAXTOP.CTL\n");
return(1);
}
else
{
while (!eof(ctlfile)) {
read(ctlfile,&ch,sizeof(ch));
if ((firstchar) && (ch=='%'))
{
/*
* got a comment character so read until EOL.
*/
while(ch!='\n')
read(ctlfile,&ch,sizeof(ch));
}
else if ((ch == '\r') || (ch == '\n') || (ch==0x1A))
{
/*
* ignore blank lines (CRLF) and the EOF marker
*/
}
else
{
/*
* something else. Get the first word and parse it.
*/
firstchar=FALSE;
while(ch==' ')
read(ctlfile,&ch,sizeof(ch));
token[0]=ch;
i=1;
while(token[i-1]!=' ')
{
read(ctlfile,&token[i],sizeof(token[i]));
i++;
}
token[i-1]='\0';
ParseToken(token,ctlfile);
firstchar = TRUE;
}
}
}
}
/****************************************************************************
* Function: ParseToken()
*
* Purpose: This function is a VERY simple token parser. Basically it's
* nothing more than several string compares. The simplicity is
* due to the small number of tokens needed in the MAXTOP.CTL file.
****************************************************************************/
void ParseToken(token,ctlfile)
char *token;
int ctlfile;
{
char ch;
int i=1;
if (!stricmp(token,maxtopPathToken))
{
/*
* found the MaxTopPath token. Skip the spaces until we come to some
* more text. From here 'till the EOL will be considered the path.
*/
if (debug)
printf("Parsed token MaxTopPath\n");
SkipSpaces(ctlfile,ch);
maxtoppath[0]=ch;
while(maxtoppath[i-1] != '\n')
{
read(ctlfile,&maxtoppath[i],sizeof(maxtoppath[i]));
i++;
}
/*
* The above loop will cause the CRLF to be inserted into the path
* variable. To get rid of this we simply null our the CR character to
* shorten the string. Q&D but it works.
*/
ClipCRLF(maxtoppath,i);
}
else if (!stricmp(token,userBBSPathToken))
{
/*
* found the UserBBSPath token. Skip the spaces until we come to some
* more text. From here 'till the EOL will be considered the path.
*/
if (debug)
printf("Parsed token UserBBSPath\n");
SkipSpaces(ctlfile,ch);
userBBSpath[0]=ch;
while(userBBSpath[i-1]!='\n')
{
read(ctlfile,&userBBSpath[i],sizeof(userBBSpath[i]));
i++;
}
/*
* The above loop will cause the CRLF to be inserted into the path
* variable. To get rid of this we simply null our the CR character to
* shorten the string. Q&D but it works.
*/
ClipCRLF(userBBSpath,i);
}
else if (!stricmp(token,titleToken))
{
/*
* Got a 'Title' token. The rest of the line will be displayed when
* the download/upload list is displayed.
*/
if (debug)
printf("Parsed token Title\n");
SkipSpaces(ctlfile,ch);
title[0]=ch;
while(title[i-1]!='\n')
{
read(ctlfile,&title[i],sizeof(title[i]));
i++;
}
ClipCRLF(title,i);
}
else
{
printf("%s - Illegal token in MAXTOP.CTL",token);
ReadToEOL(ctlfile,ch);
}
}
void Banner(void)
{
sprintf(msg,"\n\nMAXTOP Top five upload/download users utility, Version %s\n",VERSION);
Output(msg);
sprintf(msg,"Copyright (C) 1991 Douglas J. Hill. All Rights Reserved.\n\n");
Output(msg);
}
/*****************************************************************************
* Function: ParseArgs()
*
* Purpose: This function takes the command line input and parses it looking
* for command switches. Available switches are:
*
* -S: Show download/upload lists.
* -K: Local use. Do not use COMM.DLL.
* -P: Com port handle. Used only when on-line.
* -D: Debug mode. Prints diagnostic messages during run.
*****************************************************************************/
bit ParseArgs(argc, argv)
int argc;
char *argv[];
{
int i;
char *p_ch;
for (i=1; i<argc ; i++ ) {
if (!strnicmp(argv[i],"-S",2))
{
display = TRUE;
}
else if (!strnicmp(argv[i],"-D",2))
{
debug = TRUE;
}
else if (!strnicmp(argv[i],"-K",2))
{
local = TRUE;
}
else if (!strnicmp(argv[i],"-P",2))
{
p_ch=argv[i];
p_ch+=2;
hComm = (HFILE) atoi(p_ch);
}
else
return 1;
}
if ((!local) && (hComm==0))
{
local=TRUE;
}
return 0;
}
/***************************************************************************
* Function: Output()
*
* Purpose: This function takes a string and displays it on the local
* console and if we are not in local mode it also displays
* via the modem.
**************************************************************************/
void Output(str)
char *str;
{
printf("%s",str);
if ((!local) && ComIsOnline(hCommPort))
Mdm_puts(str);
}
void Terminate(rc)
int rc;
{
if (!local)
ComClose(hCommPort);
exit(rc);
}
/*****************************************************************************
* Function: Mdm_puts()
*
* Purpose: This function takes a string destined for the modem and adds
* carriage return characters after every linefeed character
* it sees.
*****************************************************************************/
void pascal Mdm_puts(char *s)
{
while (*s) {
ComPutc(hCommPort, *s++);
if (*s==10)
{ /* add carriage return to all linefeeds */
ComPutc(hCommPort, CR);
}
}
}
void InitLists(void)
{
int x;
for (x=0; x < MAX_ENTRIES ; x++ ) {
TopDownloaders[x].name[0]='\0';
TopDownloaders[x].amount=0;
TopUploaders[x].name[0]='\0';
TopUploaders[x].amount=0;
}
}