home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Micro R&D 1
/
MicroRD-CD-ROM-Vol1-1994.iso
/
os20
/
util
/
reminder_1_20.lha
/
Reminder
/
src
/
CheckMain.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-04-19
|
14KB
|
460 lines
/* ReminderCheck checks and alerts about event generated with Reminder */
/* $Id: CheckMain.c,v 1.17 1993/04/19 15:20:43 Matti_Rintala Exp $ */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <exec/types.h>
#include <dos/dosextens.h>
#include <utility/tagitem.h>
#include <exec/libraries.h>
#include <intuition/intuition.h>
#include <libraries/reqtools.h>
#ifdef __SASC
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/reqtools.h>
#endif
#ifdef _DCC
#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <clib/intuition_protos.h>
#include <clib/reqtools_protos.h>
#include <dos/dos.h>
#include <clib/dos_protos.h>
#include <workbench/startup.h>
struct Library *CxBase = NULL; /* DICE does not auto open commodities.library */
struct Library *IconBase = NULL; /* Nor icon.library */
/* DICE does not have difftime(), although its prototype is in time.h. This is
a bug in DICE, so we'll have to declare difftime() as macro */
#define difftime(a,b) ((double)(a) - (double)(b))
#endif
#include "Constants.h"
#include "CalcDate.h"
#include "ARexx.h"
/* Responses from makealarm */
#define QUIT 0
#define ACK 2
char *VersionStr = "$VER: ReminderCheck 1.20";
static int makealarm(time_t *date, const char *text);
static int groupalarm(time_t *date, struct EventNode *node, long int fpos);
static void CloseLibraries(void);
static void putack(struct EventNode *node, time_t acked);
static char *divtext(char *str, const char *text);
static int makerequest(char *buffer);
char *filename; /* Filename of the database file */
FILE *infile;
struct EventNode eventnode, groupnode, *node = NULL;
BOOL noreqtools = FALSE; /* TRUE if NOREQTOOLS tooltype is present */
BOOL noarexx = FALSE; /* TRUE if NOAREXX tooltype is present */
short maxgroup = DEFAULTMAXGROUP; /* Maximum number of grouped events in one req */
short groupno = 0; /* Number of events currently grouped */
long int *groupfpos = NULL; /* Table for record positions in grouped req */
char *grouptext = NULL; /* Text of group requester */
char *groupnext = NULL; /* Place to put next grouped event text */
short maxwidth = DEFAULTMAXWIDTH; /* Maximum width of requester line */
#ifdef _DCC
static struct FileLock *oldlock = NULL;
/* DICE uses different entry point for workbench startup */
int wbmain(struct WBStartup *msg) {
/* We have to change to correct directory */
oldlock = CurrentDir(msg->sm_ArgList[0].wa_Lock);
return main(0, (char **)msg); /* Simply call main() */
}
#endif
/* ReqTools library is only opened, if alerts are needed */
struct ReqToolsBase *ReqToolsBase = NULL;
int main(int argc, char **argv) {
UBYTE **ttypes;
long fpos;
time_t today, tim, alarm, acked, stamp;
double diff;
int response, interval;
size_t size;
atexit(CloseLibraries); /* Close libraries on exit */
#ifdef _DCC
/* With DICE we have to open commodities.library and icon.library, too */
if (!(CxBase = OpenLibrary("commodities.library", 0))) {
printf("Can't open commodities.library!\n");
exit(-1);
}
if (!(IconBase = OpenLibrary("icon.library", 0))) {
printf("Can't open icon.library!\n");
exit(-1);
}
#endif
/* Get today's date */
gettoday(&today);
/* Set node to point to eventnode */
node = &eventnode;
/* Parse arguments */
ttypes = ArgArrayInit(argc, argv);
/* Try to find database filename */
filename = ArgString(ttypes, FILETYPE, DEFAULTFILE);
/* And checking interval */
interval = ArgInt(ttypes, INTRVLTYPE, DEFAULTINTRVL);
/* And whether we use ReqTools.library or not */
noreqtools = (ArgString(ttypes, NOREQTOOLSTYPE, NULL) != NULL);
/* And whether we use ARexx or not */
noarexx = (ArgString(ttypes, NOAREXXTYPE, NULL) != NULL);
/* And maximum number of events in one grouped requester */
maxgroup = ArgInt(ttypes, MAXGROUPTYPE, DEFAULTMAXGROUP);
/* And maximum width of requester line */
maxwidth = ArgInt(ttypes, MAXWIDTHTYPE, DEFAULTMAXWIDTH);
if (maxwidth < 19)
maxwidth = 19; /* Minimum is */
/* Try to open database */
infile = fopen(filename, "r+b");
/* Clear up argument parsing */
ArgArrayDone();
/* Exit if database open failed */
if (infile == NULL)
exit(0);
/* Initialize ARexx, if permitted */
if (!noarexx)
initarexx();
/* Allocate space for grouped requester data, if needed */
if (maxgroup != 0) {
if ((grouptext = malloc((maxgroup*(TEXTLEN+1)+19)*sizeof(char))) != NULL) {
if ((groupfpos = (long int *)calloc(maxgroup, sizeof(long int))) == NULL) {
/* If memory allocation failed, free also grouptext */
free(grouptext);
grouptext = NULL;
}
}
}
/* Check the stamp */
if (fread(&stamp, 1, sizeof(time_t), infile) == sizeof(time_t)) {
tim = time(NULL);
diff = difftime(tim, stamp); /* Current interval in seconds */
if (diff >= (double)interval * 3600.0) {
/* Write new stamp */
fseek(infile, 0, SEEK_SET);
fwrite(&tim, 1, sizeof(time_t), infile);
fflush(infile);
/* Go through all events in file */
while (TRUE) {
/* Read event to node */
clearerr(infile);
while (TRUE) {
fpos = ftell(infile); /* Remember position */
size = fread(SAVEADDR(node), 1, SAVELEN(node), infile);
/* Stop looping if error or wrong number of bytes read */
if (ferror(infile) || size < SAVELEN(node))
break;
/* Also if event is not deleted */
if (node->mode != DELETEDMODE)
break;
}
/* Stop looping if end-of-file */
if (ferror(infile) || size < SAVELEN(node))
break;
/* Get event's next alarm date */
makedate(&alarm, &today, node->day, node->month, node->year, node->wday);
/* And when it has been acknowledged last time */
makedate(&acked, &today, node->aday, node->amonth, node->ayear, 0);
/* If acked time is the as alarm time, this event has already been acked */
if (acked == alarm)
continue;
/* If grouping is enabled, alarm is today and event has grouping flag
set, use grouped requester, otherwise normal */
if (grouptext != NULL && alarm == today && (node->mode & GROUPEDMASK)) {
if (groupalarm(&today, node, fpos) == QUIT)
break;
}
else {
/* If difference between now and alarm time is less than 'before'
value, alarm is made */
diff = difftime(alarm, today);
if (diff < 0.0 || diff > ((double)node->before)*((double)3600*24)) {
/* If next alarm is too far away or in past, try previous alarm */
makeprevdate(&alarm, &today, node->day, node->month,
node->year, node->wday);
/* If already acked, give up */
if (acked == alarm)
continue;
/* If difference between alarm and now is more than 'after' value,
no alarm is made */
diff = difftime(today, alarm);
if (diff < 0.0 || diff > (double)node->after*(3600.0*24.0))
continue;
}
/* Use ARexx, if requested */
makearexx(node, &alarm);
/* Make the alarm requester */
response = makealarm(&alarm, node->text);
/* If response was 'quit', stop making alarms */
if (response == QUIT)
break;
/* If it was 'acknowledged', write the ack information to file */
if (response == ACK) {
/* If autodelete flag is set, whole event can be deleted */
if (node->autodelete)
node->mode = DELETEDMODE;
else
putack(node, alarm);
fseek(infile, fpos, SEEK_SET);
size = fwrite(SAVEADDR(node), 1, SAVELEN(node), infile);
/* Stop if error */
if (ferror(infile) || size < SAVELEN(node))
break;
fflush(infile);
}
}
}
/* If grouped alarms are enabled, flush them */
if (grouptext != NULL) {
groupalarm(&today, NULL, 0);
}
}
}
fclose(infile);
exit(0);
}
/* putack puts the acknowledgement date to EventNode */
static void putack(struct EventNode *node, time_t acked) {
struct tm *tmptr;
tmptr = localtime(&acked); /* Change to struct */
node->aday = tmptr->tm_mday;
node->amonth = tmptr->tm_mon + 1;
node->ayear = tmptr->tm_year + 1900;
}
static char buffer[TEXTLEN+19]; /* Place for requester text */
/* makealarm puts up an alarm requester */
static int makealarm(time_t *date, const char *text) {
char *str = buffer;
struct tm *d;
/* Calculate date string */
d = localtime(date);
str += strftime(str, maxwidth, "%a %d-%b-%Y :\n", d); /* Print date */
divtext(str, text); /* Divide text into lines */
return makerequest(buffer); /* And present the requester to user */
}
/* groupalarm handles grouped alarms */
static int groupalarm(time_t *date, struct EventNode *node, long int fpos) {
struct tm *d;
int i, response;
long int currfpos, size;
struct EventNode *gnode = &groupnode;
/* If grouping not enabled, return */
if (grouptext == NULL)
return ACK; /* Dummy return value */
/* If node is not NULL (which means flush), add event */
if (node != NULL) {
/* If we have now the first event, calculate the date text */
if (groupno == 0) {
/* Calculate date string */
d = localtime(date);
groupnext = grouptext +
strftime(grouptext, maxwidth, "%a %d-%b-%Y :", d); /* Print date */
/* Remember the node for ARexx information */
groupnode = *node;
}
else {
/* If groupnode does not have ARexx, but new does, update groupnode */
if ((groupnode.mode & ~GROUPEDMASK) == AREXXNMODE &&
(node->mode & ~GROUPEDMASK) != AREXXNMODE)
groupnode = *node;
}
/* Add two newlines and the event text */
*groupnext++ = '\n';
*groupnext++ = '\n';
groupnext = divtext(groupnext, node->text);
/* Remember the position of the event in file */
groupfpos[groupno] = fpos;
/* There is one more event in group */
groupno++;
}
/* If maximum number of events is reached or node is NULL, make the requester */
if (groupno == maxgroup || (node == NULL && groupno != 0)) {
/* Do the ARexx */
makearexx(&groupnode, date);
/* Present the requester to user and get the response */
response = makerequest(grouptext);
/* If response was 'ACK', update the acknowledgement dates of events */
if (response == ACK) {
currfpos = ftell(infile); /* Remember current file position */
for (i = 0; i < groupno; i++) {
clearerr(infile);
fseek(infile, groupfpos[i], SEEK_SET); /* Go to correct position */
size = fread(SAVEADDR(gnode), 1, SAVELEN(gnode), infile);
/* Stop, if error or wrong number of bytes read */
if (ferror(infile) || size < SAVELEN(gnode))
break;
/* Delete or acknowledge event depending on mode */
if (gnode->autodelete)
gnode->mode = DELETEDMODE;
else
putack(gnode, *date);
/* Seek back, write the new node information and flush buffers */
fseek(infile, groupfpos[i], SEEK_SET);
size = fwrite(SAVEADDR(gnode), 1, SAVELEN(gnode), infile);
/* Stop if errors */
if (ferror(infile) || size < SAVELEN(gnode))
break;
fflush(infile);
}
/* Return to old file position */
fseek(infile, currfpos, SEEK_SET);
}
groupno = 0; /* No events in group any more */
groupnext = grouptext; /* Same goes for group text */
}
else {
response = ACK; /* If no requester was put up */
}
return response;
}
/* divtext divides text into lines and copies it */
static char *divtext(char *str, const char *text) {
int i;
while (strlen(text) > maxwidth) {
/* Find first space in the end of line */
for (i = maxwidth; i > 0 && text[i] != ' '; i--);
if (i < 2)
i = maxwidth; /* If no space found */
strncpy(str, text, i); /* Copy the line into buffer */
str += i;
text += i;
*str++ = '\n'; /* Add linefeed to end of line */
while (*text != '\0' && *text == ' ')
text++; /* Skip spaces in the beginning of new line */
}
if (*text != '\0') {
strcpy(str, text); /* Copy the last partial line */
str += strlen(text); /* Update str */
}
return str; /* Return pointer to end of added text */
}
/* makerequest puts up a given requester and returns the button pressed */
static int makerequest(char *buffer) {
/* Use ReqTools or EasyRequest depending on toolstype/cmdarg */
if (noreqtools) {
/* Structure for Intuition EasyRequest */
struct EasyStruct es = {sizeof(struct EasyStruct), 0, "Reminder",
NULL, "Go away!|Ackn|Quit!"};
es.es_TextFormat = buffer;
return (int)EasyRequest(NULL, &es, NULL, NULL);
}
else {
/* Open ReqTools library if not already open */
if (ReqToolsBase == NULL) {
if ((ReqToolsBase = (struct ReqToolsBase *)
OpenLibrary(REQTOOLSNAME, REQTOOLSVERSION)) == NULL)
return QUIT; /* If cannot open, quit program */
}
/* Make the alarm requester */
return (int)rtEZRequestTags(buffer, "_Go away!|_Ackn|_Quit!", NULL, NULL,
RT_PubScrName, (Tag)"Workbench",
RT_ReqPos, REQPOS_CENTERSCR,
RT_Underscore, (Tag)'_',
RTEZ_Flags, EZREQF_CENTERTEXT, TAG_END);
}
}
/* CloseLibraries simply closes the opened libraries */
static void CloseLibraries(void) {
if (ReqToolsBase != NULL)
CloseLibrary((struct Library *)ReqToolsBase);
/* Release ARexx */
releasearexx();
/* Free grouped requester data */
free(grouptext);
free(groupfpos);
#ifdef _DCC
/* With DICE we have to close commodities.library and icon.library, too */
if (CxBase != NULL)
CloseLibrary(CxBase);
if (IconBase != NULL)
CloseLibrary(IconBase);
/* Let's also return us to correct directory */
if (oldlock != NULL)
CurrentDir(oldlock);
#endif
}