home *** CD-ROM | disk | FTP | other *** search
- /* 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
-
- }
-