home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume17 / calentool / part17 / common.c < prev   
C/C++ Source or Header  |  1991-04-07  |  29KB  |  1,079 lines

  1. /*
  2.  * $Header: common.c,v 1.2 91/03/27 16:45:05 billr Exp $
  3.  */
  4. /*
  5.  * common.c
  6.  *
  7.  * Author: by: Bill Randle, Tektronix, Inc. <billr@saab.CNA.TEK.COM>
  8.  *
  9.  * Copyright (C) 1988, 1989, 1991 Tektronix, Inc.
  10.  *    All Rights Reserved
  11.  * Permission is hereby granted to use and modify the modifications in source
  12.  * or binary form as long as they are not sold for profit and this copyright
  13.  * notice remains intact.
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <ctype.h>
  18. #include <sys/time.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <sys/file.h>
  22. #ifndef CALENCHECK
  23. # include <suntool/sunview.h>
  24. # include <pwd.h>
  25. #endif
  26. #ifndef NO_DEFAULTS
  27. # include <sunwindow/defaults.h>
  28. #endif
  29. #include "ct.h"
  30.  
  31. struct tm save_day;
  32. struct appt_entry future[MAX_FUTURE_ENTRIES];
  33. int findex = 0;         /* index into struct future array */;
  34. int day_is_open = 0;    /* indicates when slot info is current */
  35. char apts_pathname[160], tmpapts_pathname[160];
  36. char apts_dir[128], lib_dir[128];
  37. char t_title[160];
  38.  
  39. extern struct tm current, today, First;
  40. extern struct dayslot *slots;
  41. extern char apts_pathname[], tmpapts_pathname[];
  42. extern char *progname;
  43. extern char *othername;
  44. extern int n_slots, n_tslots, read_only, new_entry;
  45. extern int otherfile, one_based, version2;
  46. extern int show_future, start_hour;
  47. extern int mainsw_state;
  48.  
  49. #ifndef CALENCHECK
  50. extern struct tm olddate, closedate;
  51. extern Frame frame, prompt_frame;
  52. extern Icon icon, rev_icon, na_icon;
  53. extern char datestr_day[];
  54. extern struct pr_prpos where;
  55. extern Pixrect *ic_pr, *rev_ic_pr, *na_ic_pr;
  56. extern int beep, beep_open;
  57. extern int appt_check_limit;
  58. extern Pixfont *sfont;
  59. extern char *smonthnames[];
  60. extern char *mailto;
  61. extern int locked;
  62. extern char *version();
  63. #endif
  64.  
  65. #ifndef NO_HOLIDAYS
  66. extern int holiday_a, holiday_c, holiday_i, holiday_j, holiday_s;
  67.  
  68. extern int a_dates(), c_dates(), i_dates(), j_dates(), s_dates();
  69. extern struct appt_entry a_appts[], c_appts[];
  70. extern struct appt_entry i_appts[], j_appts[];
  71. extern struct appt_entry s_appts[];
  72. #endif
  73. extern char *strcpy(), *strncpy(), *index();
  74.  
  75. /*
  76.  * Add an appointment entry pointed to by aptr to the day slot
  77.  * specified by slotno. This routine is also used by paste()
  78.  * when copying an entry off the save shelf. If dpyflag is true,
  79.  * then any deactivated slots are cleared on the display (used by
  80.  * paste). Also used to add a deleted entry for a specific day.
  81.  */
  82. add_to_slot(slotno, aptr, dpyflag)
  83. int slotno;
  84. struct appt_entry *aptr;
  85. int dpyflag;
  86. {
  87.     struct appt_entry *nappt, *optr;
  88.     int n_arrows, n, nbi, found = 0, i;
  89.  
  90.     if ((nappt = (struct appt_entry *)malloc(sizeof(struct appt_entry))) == NULL)
  91.         err_rpt("out of memory", FATAL);
  92.     if (aptr == NULL) {
  93.         /* fill in some needed fields */
  94.         nappt->arrows = nappt->flags = 0;
  95.         nappt->sindex = 0;
  96.         nappt->str[0] = '\0';
  97.     } else
  98.         *nappt = *aptr;
  99.     nappt->next = NULL;
  100.     /* add appt to list of appts for this slot */
  101.     if (slots[slotno].first == NULL) {
  102.         slots[slotno].first = nappt;
  103.         slots[slotno].cur_appt = nappt;
  104.     } else {
  105.         /* search for end of list */
  106.         for (optr=slots[slotno].first;optr->next;optr=optr->next)
  107.             ;
  108.         optr->next = nappt;
  109.     }
  110.     /* make sure it doesn't extend too far and truncate if neccessary */
  111.     if (slotno >= n_tslots)
  112.         nappt->arrows = 0;    /* force notes to have no arrows */
  113.     else if ((slotno + nappt->arrows) >= n_tslots)
  114.         nappt->arrows = n_tslots - slotno - 1;    /* truncate */
  115.     n_arrows = nappt->arrows;
  116.     if (nappt->flags & DELETED) {
  117.         /* look for matching non-deleted appt in list */
  118.         for (optr=slots[slotno].first;optr && !found;optr=optr->next)
  119.             if (!strcmp(nappt->str, optr->str)
  120.                 && !(optr->flags & DELETED)
  121.                 && Repeating(optr->flags)) {
  122.                 found = 1;
  123.                 break;
  124.             }
  125.         if (found && slots[slotno].cur_appt == optr) {
  126.             /* the deleted appt is the current one */
  127.             /* if it's active, undisplay it and display
  128.              * next one in list (if any)
  129.              */
  130.             if (slots[slotno].active) {
  131.                 if (slots[slotno].active > 1)
  132.                     /* there's another one here */
  133.                     next_appt(slotno, dpyflag);
  134.                 else
  135.                     deactivate_slot(slotno, dpyflag);
  136.                 /* adjust reference counts */
  137.                 slots[slotno].count--;
  138.                 slots[slotno].active--;
  139.                 i = 0;
  140.                 while (++i <= n_arrows)
  141.                     --slots[slotno+i].count;
  142.             } else {
  143.                 /* currently inactive */
  144.                 /* set current to next one in the list */
  145.                 if (optr->next)
  146.                     slots[slotno].cur_appt = optr->next;
  147.                 else
  148.                     slots[slotno].cur_appt = slots[slotno].first;
  149.                 /* adjust the counts */
  150.                 slots[slotno].active--;
  151.                 while (n_arrows >= 0)
  152.                     slots[slotno+(n_arrows--)].count--;
  153.             }
  154.         } else {
  155.             /* just adjust the counts */
  156.             slots[slotno].active--;
  157.             while (n_arrows >= 0)
  158.                 slots[slotno+(n_arrows--)].count--;
  159.         }
  160.     } else {
  161.         /* look for matching deleted appt in list */
  162.         if (Repeating(nappt->flags)) {
  163.             for (optr=slots[slotno].first;optr && !found;optr=optr->next)
  164.                 if (!strcmp(nappt->str, optr->str) && optr->flags & DELETED) {
  165.                     found = 1;
  166.                     break;
  167.                 }
  168.             if (found) {
  169.                 /* just adjust reference counts and return */
  170.                 slots[slotno].active++;
  171.                 while (n_arrows >= 0)
  172.                     slots[slotno+(n_arrows--)].count++;
  173.                 return;
  174.             }
  175.         }
  176.         /*
  177.          * Make sure there are no overlaps with the appt we
  178.          * are adding. If there are, hide the overlapping appt.
  179.          */
  180.         if (slots[slotno].active)
  181.             deactivate_slot(slotno, dpyflag);
  182.         /* set current one to the new one */
  183.         slots[slotno].cur_appt = nappt;
  184.         /* now go back and put in the info for the appt we're inserting */
  185.         slots[slotno].count++;
  186.         slots[slotno].active++;
  187.         if (n_arrows > 0) {
  188.             slots[slotno+n_arrows].count++;
  189.             while (--n_arrows > 0)
  190.                 slots[slotno+n_arrows].count++;
  191.         }
  192.     }
  193.     if (dpyflag)
  194.         draw_day_appts();    /* redraw display */
  195. }
  196.  
  197. /* add a note to the current day */
  198. add_note(appt)
  199. struct appt_entry *appt;
  200. {
  201.     int    slotno, found = 0;
  202.     struct appt_entry *optr;
  203.  
  204.     /* This used to just find a free slot and add the note
  205.      * to it. However, with deleted notes we need to find
  206.      * the matching slotno (if it exists) to make sure that
  207.      * the deleted and non-deleted notes end up in the same
  208.      * slot number (so they won't be displayed).
  209.      */
  210.     if (appt->flags & DELETED) {
  211.         /* look for matching non-deleted note */
  212.         for (slotno=n_tslots; slotno<n_slots && !found; slotno++) {
  213.             if (!slots[slotno].active)
  214.                 break;    /* no more notes */
  215.             for (optr=slots[slotno].first;optr;optr=optr->next) {
  216.                 if (!strcmp(appt->str, optr->str)
  217.                     && !(optr->flags & DELETED)
  218.                     && Repeating(optr->flags)) {
  219.                     found = 1;
  220.                     break;
  221.                 }
  222.             }
  223.         }
  224.     } else {
  225.         /* look for free slot and/or matching deleted note */
  226.         for (slotno=n_tslots; slotno<n_slots && !found; slotno++) {
  227.             if (!slots[slotno].active)
  228.                 break;    /* no more notes */
  229.             for (optr=slots[slotno].first;optr;optr=optr->next)
  230.                 if (!strcmp(appt->str, optr->str)
  231.                     && (optr->flags & DELETED)
  232.                     && Repeating(appt->flags)) {
  233.                     found = 1;
  234.                     break;
  235.                 }
  236.         }
  237.     }
  238.     if (found)
  239.         --slotno;  /* for loop incremented slotno */
  240.     if (slotno == n_slots) {
  241.         /* overflow of notes field, so
  242.          * add to last note field list
  243.          */
  244.         slotno = n_slots - 1;
  245.     }
  246.     add_to_slot(slotno, appt, FALSE);
  247. }
  248.  
  249. /*
  250.  * Fills in appointments for the day.  
  251.  * The ".tmp.aptsXXXXX" file is filled out
  252.  * with all the lines from the ".appointments" file 
  253.  * which do not pertain to the current day.
  254.  */
  255. int
  256. get_day_appts()
  257. {
  258.     FILE *apts, *temp_apts;
  259.     int slotno, n_arrows, i, j, k;
  260.     int read_stat, some_appt = 0;
  261.     int runl;
  262.     struct appt_entry appt;
  263.     struct appt_entry *nappt, *aptr;
  264.     char buf[MAX_STRLEN], *sptr;
  265.  
  266.     if ((apts = fopen(apts_pathname, "r")) == NULL)
  267.         err_rpt("can't open appointments file", FATAL);
  268.  
  269.     if (!read_only)
  270.             if ((temp_apts = fopen(tmpapts_pathname, "w")) == NULL)
  271.             err_rpt("can't open temp file for writing", FATAL);
  272.  
  273.     for (i=0; i<n_slots; i++) {    /* init each slot */
  274.         slots[i].count = 0;
  275.         slots[i].cur_appt = NULL;
  276.         slots[i].first = NULL;
  277.         slots[i].active = 0;
  278.     }
  279.     First = current;
  280.     findex = 0;
  281.  
  282. #ifndef NO_HOLIDAYS
  283.     /*
  284.      * First check to see if the user has selected any holiday
  285.      * options and add them in.
  286.      */
  287.     working(TRUE);
  288.     if (holiday_a) {
  289.         j = a_dates(holiday_a);
  290.         for (k=0; k<j; k++)
  291.             if (ymd2_compare(¤t, &a_appts[k]) == 0) {
  292.                 some_appt |= (holiday_a == 1 ? SOME_MKNOTES : SOME_NOTES);
  293.                 add_note(&a_appts[k]);
  294.             }
  295.     }
  296.     working(FALSE);
  297.     if (holiday_c) {
  298.         j = c_dates(holiday_c);
  299.         for (k=0; k<j; k++)
  300.             if (ymd2_compare(¤t, &c_appts[k]) == 0) {
  301.                 some_appt |= (holiday_c == 1 ? SOME_MKNOTES : SOME_NOTES);
  302.                 add_note(&c_appts[k]);
  303.             }
  304.     }
  305.     working(TRUE);
  306.     if (holiday_i) {
  307.         j = i_dates(holiday_i);
  308.         for (k=0; k<j; k++)
  309.             if (ymd2_compare(¤t, &i_appts[k]) == 0) {
  310.                 some_appt |= (holiday_i == 1 ? SOME_MKNOTES : SOME_NOTES);
  311.                 /* look for \n */
  312.                 if ((sptr = index(i_appts[k].str, '\n')) != NULL) {
  313.                     appt = i_appts[k];
  314.                     /* two notes in one */
  315.                     strcpy(buf, appt.str);
  316.                     *sptr = '\0';
  317.                     add_note(&appt);
  318.                     /* now second half of string in the next note */
  319.                     strcpy(appt.str, &buf[(int)(sptr-appt.str)+1]);
  320.                     add_note(&appt);
  321.                 } else
  322.                     add_note(&i_appts[k]);
  323.             }
  324.     }
  325.     working(FALSE);
  326.     if (holiday_j) {
  327.         j = j_dates(holiday_j);
  328.         for (k=0; k<j; k++)
  329.             if (ymd2_compare(¤t, &j_appts[k]) == 0) {
  330.                 some_appt |= (holiday_j == 1 ? SOME_MKNOTES : SOME_NOTES);
  331.                 add_note(&j_appts[k]);
  332.             }
  333.     }
  334.     working(TRUE);
  335.     if (holiday_s) {
  336.         j = s_dates(holiday_s);
  337.         for (k=0; k<j; k++)
  338.             if (ymd2_compare(¤t, &s_appts[k]) == 0) {
  339.                 some_appt |= (holiday_s == 1 ? SOME_MKNOTES : SOME_NOTES);
  340.                 add_note(&s_appts[k]);
  341.             }
  342.     }
  343.     working(FALSE);
  344. #endif
  345.             
  346.     /*
  347.      * now go thru the appointments file
  348.      */
  349.     while ((read_stat=get_aentry(apts, &appt, FALSE, FALSE, First.tm_mon+1)) != EOF) {
  350.         if (read_stat)
  351.             continue;    /* read error (ignore) */
  352.         if (appt.flags & A_COMMENT) {
  353.             if (put_aentry(temp_apts, &appt)) {
  354.                 /* write error */
  355.                 break;
  356.             }
  357.             continue;
  358.         }
  359.         current.tm_year = appt.year;
  360.         current.tm_mon = appt.month;
  361.         current.tm_mday = appt.day;
  362.         if (appt.flags & ALL_YEARS)
  363.             current.tm_year = First.tm_year;
  364.         if (appt.flags & ALL_MONTHS)
  365.             current.tm_mon = First.tm_mon;
  366.         if (appt.flags & ALL_DAYS)
  367.             current.tm_mday = First.tm_mday;
  368.         else if (appt.flags & EVERY_MON_FRI) {
  369.             if (First.tm_wday >= MON && First.tm_wday <= FRI)
  370.                 current.tm_mday = First.tm_mday;
  371.             else
  372.                 current.tm_mday = 0;
  373.         } else if (appt.flags & EVERY_SOMEDAY) {
  374.             if ((Pickday(appt.flags) == First.tm_wday)
  375.                 && (chk_week(appt.repeat, First.tm_mday))) {
  376.                 if (appt.flags & RUN) {
  377.                     runl = appt.runlength;
  378.                     find_date(&appt);
  379.                     while (ymd_compare(current, First) < 0 && --runl) {
  380.                         current.tm_mday += 7;
  381.                         find_date(&appt);
  382.                     }
  383.                 } else
  384.                     current.tm_mday = First.tm_mday;
  385.             } else
  386.                 current.tm_mday = 0;
  387.         } else if (appt.flags & REPEAT) {
  388.             if (appt.flags & RUN)
  389.                 runl = appt.runlength;
  390.             else
  391.                 runl = 1;
  392.             while (ymd_compare(current, First) < 0 && runl) {
  393.                 if (appt.flags & RUN)
  394.                     --runl;
  395.                 if (runl) {
  396.                     current.tm_mday += appt.repeat;
  397.                     fix_current_day();
  398.                 }
  399.             }
  400.         }
  401.         if (ymd_compare(current, First) == 0) {
  402.             /* if it's for this day, fill in slot info */
  403.             if (appt.flags & A_NOTE) {
  404.                 /* notes section */
  405.                 add_note(&appt);
  406.                 if (appt.flags & MARKED)
  407.                     /* marked note */
  408.                     some_appt |= SOME_MKNOTES;
  409.                 else
  410.                     /* regular note */
  411.                     some_appt |= SOME_NOTES;
  412.             } else {
  413.                 /* regular appointment */
  414.                 slotno = (appt.hour-start_hour) * 2 + appt.minute / 30;
  415.                 if (slotno < 0)
  416.                     slotno = 0;
  417.                 if (slotno >= n_tslots)
  418.                     slotno = n_tslots - 1;
  419.                 /* add this appt to the list of appts for the slot */
  420.                 /* and update all the reference counts */
  421.                 add_to_slot(slotno, &appt, FALSE);
  422.                 some_appt |= SOME_APPTS;
  423.             }
  424.         } else if (appt.flags & LOOKAHEAD) {
  425.             /* This lookahead appt was not for today, so
  426.              * put it in the temp file.
  427.              */
  428.             if (put_aentry(temp_apts, &appt)) {
  429.                 /* write error */
  430.                 break;
  431.             }
  432.             if (appt.flags & EVERY_SOMEDAY) {
  433.                 /* find next occurance of this appt */
  434.                 /* starting from the current day */
  435.                 current.tm_mday = First.tm_mday;
  436.                 fix_current_day();
  437.                 find_date(&appt); /* may modify current */
  438.             }
  439.             if (ymd_compare(current, First) > 0) {
  440.                 /* this appt is happening in
  441.                  * the future, so remind us of it if
  442.                  * it is within the lookahead window.
  443.                  */
  444.                 save_day = current;
  445.                 current.tm_mday -= appt.lookahead;
  446.                 fix_current_day();
  447.                 if (ymd_compare(current, First) <=0) {
  448.                     /* save this one for the future popup window */
  449.                     if (findex > MAX_FUTURE_ENTRIES-1) {
  450.                         err_rpt("Too many future reminders", NON_FATAL);
  451.                         continue;
  452.                     }
  453.                     future[findex] = appt;
  454.                     /* fix up ymd */
  455.                     future[findex].year = save_day.tm_year;
  456.                     future[findex].month = save_day.tm_mon;
  457.                     future[findex].day = save_day.tm_mday;
  458.                     ++findex;
  459.                     some_appt |= SOME_FUTURES;
  460.                 }
  461.             }
  462.                 } else {     /* line is not for today */
  463.             /* copy it to temp file */
  464.             if (put_aentry(temp_apts, &appt)) {
  465.                 /* write error */
  466.                 break;
  467.             }
  468.         }
  469.         }
  470.     if (!read_only) {
  471.         if (ferror(temp_apts))
  472.             err_rpt("write on temp file failed", FATAL);
  473.             fclose(temp_apts);        
  474.     }
  475.         fclose(apts);             
  476.     current = First;
  477.     fix_current_day();
  478.     orphan_check();
  479.  
  480.     return(some_appt);
  481. }
  482.  
  483.  
  484. /* check for match on weekly re-ocurring appts */
  485. chk_week(repeat, curday)
  486. int repeat, curday;
  487. {
  488.     int weeknr = 0;
  489.  
  490.     if ((repeat & ALL_WEEKS) == ALL_WEEKS)
  491.         return(1);    /* every week */
  492.     if ((repeat & LAST_WEEK) && ((curday+7) > monthlength(current.tm_mon)))
  493.         return(1);    /* last week in month */
  494.  
  495.     while (curday > 7) {
  496.         /* find which week this day is in */
  497.         curday -= 7;
  498.         weeknr++;
  499.     }
  500.     if (repeat & (0x1<<weeknr))
  501.         return(1);
  502.     
  503.     return(0);    /* no match */
  504. }
  505.  
  506.  
  507. /*
  508.  * get date of next occurrance of a weekly repeated appt
  509.  * (it may bridge into next week, month or year)
  510.  */
  511. find_date(appt)
  512. struct appt_entry *appt;
  513. {
  514.     struct tm save;
  515.     int runl;
  516.  
  517.     save = current;
  518.     fix_current_day();
  519.     /* set current to match dow of repeated appt */
  520.     if (appt->flags & EVERY_MON_FRI) {
  521.         if (current.tm_wday == SUN)
  522.             current.tm_mday++;
  523.         else if (current.tm_wday == SAT)
  524.             current.tm_mday += 2;
  525.     } else 
  526.         current.tm_mday += Pickday(appt->flags) - current.tm_wday;
  527.     fix_current_day();
  528.     if (ymd_compare(current, save) < 0) {
  529.         /* already happened, so start looking next week */
  530.         current.tm_mday += 7;
  531.         fix_current_day();
  532.     }
  533.     /* search for first matching week */
  534.     while (!chk_week(appt->repeat, current.tm_mday)) {
  535.         current.tm_mday += 7;
  536.         fix_current_day();
  537.     }
  538.     /* now check to make sure this is legal, i.e. there
  539.      * were no month or year restrictions
  540.      */
  541.     if (!(appt->flags & RUN) && ((!(appt->flags & ALL_YEARS) && current.tm_year != save.tm_year)
  542.        || (!(appt->flags & ALL_MONTHS) && current.tm_mon != save.tm_mon)))
  543.         /* invalid date, due to month or year wrap */
  544.         current = save;
  545. }
  546.  
  547. /*
  548.  * orphan_check() - check each slot for orphan appointments. Orphans
  549.  * are a deleted recurring appointment where it is deleted on a
  550.  * specific date and the original appointment no longer exists.
  551.  */
  552. orphan_check()
  553. {
  554.     int i, n_arrows;
  555.     struct appt_entry *aptr, *optr;
  556.  
  557.     for (i=0; i<n_slots; i++) {
  558.         while (slots[i].first != NULL) {
  559.             optr = slots[i].first;
  560.             if (chk_deleted(&slots[i], optr) == -1) {
  561.                 /* just adjust the counts */
  562.                 n_arrows = optr->arrows;
  563.                 while (n_arrows >= 0)
  564.                     slots[i+(n_arrows--)].count++;
  565.                 slots[i].active++;
  566.                 if (optr->next) {
  567.                     if (slots[i].cur_appt == slots[i].first)
  568.                         slots[i].cur_appt = slots[i].first->next;
  569.                     slots[i].first = slots[i].first->next;
  570.                 } else {
  571.                     /* last one */
  572.                     if (slots[i].cur_appt == slots[i].first)
  573.                         slots[i].cur_appt = NULL;
  574.                     slots[i].first = NULL;
  575.                     slots[i].active = 0;
  576.                 }
  577.                 free(optr);
  578.                 new_entry = 1;
  579.             } else {
  580.                 while (aptr = optr->next) {
  581.                     if (chk_deleted(&slots[i], aptr) == -1) {
  582.                         /* just adjust the counts */
  583.                         n_arrows = aptr->arrows;
  584.                         while (n_arrows >= 0)
  585.                             slots[i+(n_arrows--)].count++;
  586.                         slots[i].active++;
  587.                         optr->next = aptr->next;
  588.                         if (slots[i].cur_appt == aptr)
  589.                             slots[i].cur_appt = aptr->next;
  590.                         free(aptr);
  591.                         new_entry = 1;
  592.                     } else {
  593.                         optr = aptr;
  594.                     }
  595.                 }
  596.                 break;
  597.             }
  598.         }
  599.         if (chk_deleted(&slots[i], slots[i].cur_appt)) {
  600.             next_appt(i, FALSE);
  601.             if (slots[i].cur_appt == NULL)
  602.                 /* only deleted appts, so reset to first */
  603.                 slots[i].cur_appt = slots[i].first;
  604.         }
  605.     }
  606. }
  607.  
  608. /* check to see if appt is deleted */
  609. int
  610. chk_deleted(slptr, aptr)
  611. struct dayslot *slptr;
  612. struct appt_entry *aptr;
  613. {
  614.     int found = 0;
  615.     struct appt_entry *optr;
  616.  
  617.     if (slptr->first == NULL || aptr == NULL)
  618.         return(0);
  619.     if (aptr->flags & DELETED) {
  620.         /* run through the list and look for a matching
  621.          * repeating non-deleted entry. If we don't find one,
  622.          * this appt is a deleted orphan.
  623.          */
  624.         for (optr=slptr->first; optr; optr=optr->next)
  625.             if (!(optr->flags & DELETED) && Repeating(optr->flags))
  626.                 /* now see if the current one matches */
  627.                 if (!strcmp(optr->str, aptr->str))
  628.                     return(1);
  629.         return(-1);  /* orphan */
  630.     }
  631.     if (Repeating(aptr->flags)) {
  632.         /* run through the list to see if there are any deleted */
  633.         for (optr=slptr->first; optr; optr=optr->next)
  634.             if (optr->flags & DELETED) {
  635.                 /* now see if the current one matches */
  636.                 if (!strcmp(optr->str, aptr->str))
  637.                     return(1);
  638.             }
  639.     }
  640.     
  641.     return(0);
  642. }
  643.  
  644. /*
  645.  * When timer has expired check to see if we are close to an
  646.  * appointment. If so, switch to the other icon so we have a
  647.  * visual indication and beep the console (if enabled).
  648.  */
  649. check_calendar()
  650. {
  651.     int appt_pending = 0;     /* no appointments pending */
  652.     int slotno = 0;     /* start with first timeslot */
  653.     int smin, tmin;
  654.     int sno, save_ro;
  655.     static int echoed_sno = -1;
  656.     static int new_day = 0;
  657.     FILE *console;
  658.     struct appt_entry *aptr;
  659.     struct tm Saveday;
  660.     char *getenv();
  661.     static time_t lastmod = (time_t)0;
  662.     struct stat stbuf;
  663. #ifndef CALENCHECK
  664.     char msgfile[128];
  665.     int some_appts = 0;    /* no appointments today */
  666.     static int icon_in_use = STD_ICON;
  667.     Icon cur_icon;
  668.     FILE *msgf;
  669. #endif
  670.  
  671. #ifndef CALENCHECK
  672.     if (locked)    /* can't change yet */
  673.         return;
  674.     lock_cursors();
  675.     locked++;    /* make it unique to us */
  676.     strcpy(msgfile, getenv("HOME"));
  677.     strcat(msgfile, "/.msgfile");
  678. #endif
  679.  
  680.     sno = echoed_sno;    /* assume no console echo */
  681.     get_today();
  682.     stat(apts_pathname, &stbuf);
  683.     Saveday = current;
  684.     /*
  685.      * Check to see if we're not displaying today.
  686.      * (Or in the case of "calencheck" if the appointments
  687.      * file has been modified.) If so, we need to update our
  688.      * slot information.
  689.      */
  690. #ifndef CALENCHECK
  691.     if ((int)window_get(frame, FRAME_CLOSED) && ymd_compare(closedate, today) != 0)
  692.         new_day++;
  693. #endif
  694.     if (ymd_compare(current, today) != 0 || new_day) {
  695.         if (day_is_open)
  696.             close_day();
  697.         current = today;
  698. #ifdef CALENCHECK
  699.         new_day++;
  700. #endif
  701.     }
  702.     if (stbuf.st_mtime > lastmod) {
  703.         lastmod = stbuf.st_mtime;
  704.         day_is_open = FALSE;    /* force reading appts file */
  705.         sno = echoed_sno = -1;
  706.     }
  707.     if (day_is_open) {
  708.         /* slot info is current */
  709. #ifndef CALENCHECK
  710.         unlock_cursors();
  711. #endif
  712.     } else {
  713. #ifdef CALENCHECK
  714.         (void)get_day_appts();
  715. #else
  716.         save_ro = read_only;
  717.         read_only = 1;    /* force read only mode */
  718.         err2console(TRUE);
  719.         (void)get_day_appts();
  720.         err2console(FALSE);
  721. #endif
  722.         day_is_open = TRUE;
  723.         read_only = save_ro;
  724.         if (new_day)
  725.             sno = echoed_sno = -1;
  726.     }
  727.  
  728.     slotno = (today.tm_hour - start_hour)*2 + today.tm_min/30;
  729.     if (slotno < 0)
  730.         slotno = 0;
  731.     /* our current time (minutes past midnight) */
  732.     tmin = today.tm_hour * 60 + today.tm_min;
  733.     if (slots[slotno].count > 0 && slotno < n_tslots)
  734.         /* something going on now */
  735.         appt_pending++;
  736.     while (slotno < n_tslots) {
  737.         if (slots[slotno].count > 0) {
  738.             /* convert slotno back to time difference */
  739.             smin = start_hour * 60 + slotno * 30 - tmin;
  740.             if (smin < 0)
  741.                 smin = 0;
  742.             if (slots[slotno].active) {
  743.                 /* get all valid appts at this time */
  744.                 for (aptr=slots[slotno].first; aptr;
  745.                     aptr=aptr->next)
  746.                     if (!chk_deleted(&slots[slotno], aptr)
  747.                         && aptr->warn
  748.                         && (smin <= aptr->warn)) {
  749.                         sno = slotno;
  750.                         appt_pending++;
  751.                         break;
  752.                     }
  753.                 if (sno > echoed_sno)
  754.                     break;
  755.             }
  756.         }
  757.         slotno++;
  758.     }
  759.     if (!appt_pending) {
  760. #ifndef CALENCHECK
  761.         /*
  762.          * Is there anything happening today (optionally
  763.          * including memos)?
  764.          * Don't care about things that happened before now
  765.          * so start looking at <slotno>, which is set to
  766.          * reflect the current hour (or 0 if before start_hour).
  767.          */
  768.         slotno = (today.tm_hour - start_hour)*2 + today.tm_min/30;
  769.         if (slotno < 0)
  770.             slotno = 0;
  771.         /*
  772.          * appt_check_limit is typically either "n_tslots"
  773.          * or "n_slots" depending on whether we include the
  774.          * notes section when indicating that we still have
  775.          * appts today.
  776.          */
  777.         while (slotno < appt_check_limit)
  778.             if (slots[slotno++].count) {
  779.                 some_appts++;
  780.                 break;
  781.             }
  782.         /* maybe change the icon */
  783.         if ((some_appts && (icon_in_use != STD_ICON)) ||
  784.            (!some_appts && (icon_in_use != NA_ICON))) {
  785.             window_set(frame,
  786.                 FRAME_ICON, (some_appts?
  787.                 icon : na_icon),
  788.                 0);
  789.             icon_in_use = some_appts ? STD_ICON : NA_ICON;
  790.         }
  791.         /* clean out the ~/.msgfile file */
  792.         if (beep && ((msgf = fopen(msgfile, "w")) != NULL)) {
  793.             fprintf(msgf, "I'm out running around.");
  794.             fclose(msgf);
  795.         }
  796. #endif
  797.     } else {
  798.          /* notify the user via the console (once) ... */
  799. #ifdef CALENCHECK
  800.         if (sno > echoed_sno) {
  801.             echoed_sno = sno;
  802.             /* get all valid appts at this time */
  803.             for (aptr=slots[sno].first; aptr; aptr=aptr->next)
  804.                 if (!chk_deleted(&slots[sno], aptr)) {
  805.                     if (getenv("WINDOW_PARENT") != NULL
  806.                         && (console = fopen("/dev/console", "w")) != NULL) {
  807.                         fprintf(console, "<< %s >> %s\n",
  808.                             progname, aptr->str);
  809.                         fclose(console);
  810.                     } else {
  811.                         fprintf(stderr, "\007\007<< %s >> %s\n",
  812.                             progname, aptr->str);
  813.                     }
  814.                 }
  815.         }
  816. #else
  817.         if ((beep || beep_open) && sno > echoed_sno) {
  818.             echoed_sno = sno;
  819.             window_bell(frame);
  820.             if (beep_open) {
  821.                 olddate = Saveday = today;
  822.                 mainsw_state = DISPLAYING_DAY;
  823.                 window_set(frame, FRAME_CLOSED, FALSE, 0);
  824.             }
  825.             if (beep)
  826.                 if ((console = fopen("/dev/console", "w")) != NULL) {
  827.                     /* get all valid appts at this time */
  828.                     for (aptr=slots[sno].first; aptr;
  829.                         aptr=aptr->next)
  830.                         if (!chk_deleted(&slots[sno], aptr))
  831.                             fprintf(console, "<< %s >> %s\n", progname, aptr->str);
  832.                     fclose(console);
  833.                 }
  834.             /*
  835.              * also put a copy in ~/.msgfile, in case
  836.              * nlock(1) is running
  837.              */
  838.             if ((msgf = fopen(msgfile, "w")) != NULL) {
  839.                 fprintf(msgf, "%s", slots[sno].cur_appt->str);
  840.                 fclose(msgf);
  841.             }
  842.         }
  843.          /* ... and change the icon */
  844.         if (icon_in_use != REV_ICON) {
  845.             window_set(frame,
  846.                 FRAME_ICON, rev_icon,
  847.                 0);
  848.             icon_in_use = REV_ICON;
  849.         }
  850. #endif
  851.     }
  852. #ifdef CALENCHECK
  853.     if (new_day)
  854.         Saveday = today;
  855. #else
  856.     if (new_day && (int)window_get(frame, FRAME_CLOSED)) {
  857.         /* update times so that it opens on today */
  858.         closedate = olddate = Saveday = today;
  859.         /* update date field of the icons */
  860.         sprintf(datestr_day, "%d", today.tm_mday);
  861.         /* replace the date */
  862.         where.pr = ic_pr;
  863.         where.pos.x = 13;
  864.         where.pos.y = 49 + 5;
  865.         pr_rop(where.pr, 14, 47, 10, 8, PIX_CLR, NULL, 0, 0);
  866.         pr_rop(where.pr, 40, 47, 16, 8, PIX_CLR, NULL, 0, 0);
  867.         pf_ttext(where, PIX_NOT(PIX_SRC), sfont, datestr_day);
  868.         where.pr = na_ic_pr;
  869.         pr_rop(where.pr, 14, 47, 10, 8, PIX_CLR, NULL, 0, 0);
  870.         pr_rop(where.pr, 40, 47, 16, 8, PIX_CLR, NULL, 0, 0);
  871.         pf_ttext(where, PIX_NOT(PIX_SRC), sfont, datestr_day);
  872.         where.pr = rev_ic_pr;
  873.         pr_rop(where.pr, 14, 47, 10, 8, PIX_SET, NULL, 0, 0);
  874.         pr_rop(where.pr, 40, 47, 16, 8, PIX_SET, NULL, 0, 0);
  875.         pf_ttext(where, PIX_SRC, sfont, datestr_day);
  876.         where.pos.x = 39;
  877.         where.pr = ic_pr;
  878.         pf_ttext(where, PIX_NOT(PIX_SRC), sfont, smonthnames[today.tm_mon]);
  879.         where.pr = na_ic_pr;
  880.         pf_ttext(where, PIX_NOT(PIX_SRC), sfont, smonthnames[today.tm_mon]);
  881.         where.pr = rev_ic_pr;
  882.         pf_ttext(where, PIX_SRC, sfont, smonthnames[today.tm_mon]);
  883.         icon_set(icon, ICON_IMAGE, ic_pr, 0);
  884.         icon_set(rev_icon, ICON_IMAGE, rev_ic_pr, 0);
  885.         icon_set(na_icon, ICON_IMAGE, na_ic_pr, 0);
  886.         switch (icon_in_use) {
  887.             case STD_ICON:
  888.                 window_set(frame, FRAME_ICON, icon, 0);
  889.                 break;
  890.             case REV_ICON:
  891.                 window_set(frame, FRAME_ICON, rev_icon, 0);
  892.                 break;
  893.             case NA_ICON:
  894.                 window_set(frame, FRAME_ICON, na_icon, 0);
  895.                 break;
  896.         }
  897.         new_day = 0;
  898.         show_future = 1;    /* show future appts again */
  899.     }
  900. #endif
  901. #ifndef CALENCHECK
  902.     current = Saveday;
  903.     err2console(TRUE);
  904.     (void)get_day_appts();
  905.     err2console(FALSE);
  906.     if (locked == 2)
  907.         unlock_cursors();
  908. #endif
  909. }
  910.  
  911. do_files(window_prompt)
  912. int window_prompt;
  913. {
  914.     char *slash, *default_ptr, *envptr;
  915.     char buff[80];
  916.     int to_slash, getpid(), fd, errflag, numask;
  917.     struct passwd *pw;
  918.     struct stat statbuf;
  919.     FILE *appts;
  920.     char *strcpy(), *rindex(), *getenv();
  921.  
  922.     /* the tmp file */
  923.     sprintf(tmpapts_pathname, "/tmp/appts%d", getpid());
  924.     if (otherfile) {
  925.         strcpy(apts_pathname, othername);
  926.         if ((slash = rindex(apts_pathname, '/')) != NULL) {
  927.             to_slash = slash - apts_pathname;
  928.             strncpy(apts_dir, apts_pathname, to_slash);
  929.             apts_dir[to_slash] = '\0';
  930.         } else {
  931.             strcpy(apts_dir, ".");
  932.         }
  933.     } else {
  934. #ifndef NO_DEFAULTS
  935.         if ((default_ptr = defaults_get_string("/CalenTool/Appts", NULL, 0)) != NULL) {
  936.             if ((slash = rindex(default_ptr, '/')) != NULL) {
  937.                 to_slash = slash - default_ptr;
  938.                 strncpy(apts_dir, default_ptr, to_slash);
  939.                 apts_dir[to_slash] = '\0';
  940.             } else {
  941.                 strcpy(apts_dir, ".");
  942.             }
  943.         } else
  944. #endif
  945.         if ((envptr = getenv("CALENTOOL_DIR")) != NULL) {   
  946.             strcpy(apts_dir, envptr);
  947. #ifndef CALENCHECK
  948.         } else if (mailto) {
  949.             if ((pw = getpwnam(mailto)) == NULL)
  950.                 /* no entry */
  951.                 exit(1);
  952.             envptr = pw->pw_dir; /* home directory */
  953.             strcpy(apts_dir, envptr);
  954. #endif
  955.         } else if ((envptr = getenv("HOME")) != NULL) {   
  956.             strcpy(apts_dir, envptr);
  957.         } else {   
  958.             apts_dir[0] = '\0';
  959.         }
  960.         if (*apts_dir) {
  961.             /* prepend directory on pathnames */
  962.             sprintf(apts_pathname, "%s/.appointments", apts_dir);
  963.         } else {
  964.             /* use current directory */
  965.             strcpy(apts_pathname, ".appointments");
  966.         }
  967.     }
  968.     
  969.     /* directory for date/event data files */
  970. #ifndef NO_DEFAULTS
  971.     if ((default_ptr = defaults_get_string("/CalenTool/LibDir", NULL, 0)) != NULL)
  972.         strcpy(lib_dir, default_ptr);
  973.     else
  974. #endif
  975.         strcpy(lib_dir, DATELIB_DIR);
  976.  
  977.     errflag = 0;
  978.     if (access(apts_pathname, R_OK) == -1) {
  979. #ifndef CALENCHECK
  980.         if (window_prompt) {
  981.             fprintf(stderr, "nonexistant file\n");
  982.             sprintf(buff, "Cannot access calendar file %s - create?", apts_pathname);
  983.             create_prompt_frame(buff, TRUE);
  984.             if ((int)window_loop(prompt_frame) == 0) {
  985.                 /* try to create the file */
  986.                 fprintf(stderr, "creating file\n");
  987.                 if ((fd=open(apts_pathname, O_CREAT|O_RDWR, 0644)) <= 0) {
  988.                     perror(apts_pathname);
  989.                     errflag = 1;
  990.                     fprintf(stderr, "..error\n");
  991.                 } else {
  992.                     if (write(fd, HEADER, sizeof(HEADER)) != sizeof(HEADER)) {
  993.                         perror("writing header");
  994.                         errflag = 1;
  995.                     }
  996.                     close(fd);
  997.                     fprintf(stderr, "..wrote header\n");
  998.                     one_based = 1;
  999.                 }
  1000.             } else {
  1001.                 fprintf(stderr, "window_ret != 0\n");
  1002.                 errflag = 1;
  1003.             }
  1004.             window_set(prompt_frame, WIN_SHOW, FALSE, 0);
  1005.             if (errflag)
  1006.                 return(1);
  1007.         } else {
  1008. #endif
  1009.             fprintf(stderr, "Cannot access calendar file %s - create? ", apts_pathname);
  1010.             fgets(buff, 80, stdin);
  1011.             if (buff[0] == 'y' || buff[0] == 'Y') {
  1012.                 if ((fd=open(apts_pathname, O_CREAT|O_RDWR, 0644)) <= 0) {
  1013.                     perror(apts_pathname);
  1014.                     return(1);
  1015.                 } else {
  1016.                     if (write(fd, HEADER, sizeof(HEADER)) != sizeof(HEADER)) {
  1017.                         perror("writing header");
  1018.                         close(fd);
  1019.                         return(1);
  1020.                     }
  1021.                     close(fd);
  1022.                     one_based = 1;
  1023.                 }
  1024.             } else
  1025.                 return(1);
  1026.         }
  1027. #ifndef CALENCHECK
  1028.     }
  1029.     if (!read_only)
  1030.         if (access(apts_pathname, W_OK) == -1)
  1031.             read_only = 1;
  1032.     /*
  1033.      * set permissions on tmp file based on .appointments file
  1034.      * with the expception that we need at least write permission
  1035.      * for the owner.
  1036.      */
  1037.     (void)stat(apts_pathname, &statbuf);
  1038.     numask = ~statbuf.st_mode & 0077;  /* yes, this is octal 77 */
  1039.     (void)umask(numask);
  1040.  
  1041.     /* update base frame label, if the tool is running */
  1042.     if (frame) {
  1043.         strcpy(t_title, version());
  1044.         if (read_only)
  1045.             strcat(t_title, " [Read Only]");
  1046.         strcat(t_title, "  -  ");
  1047.         strcat(t_title, apts_pathname);
  1048.         window_set(frame, FRAME_LABEL, t_title, 0);
  1049.     }
  1050. #endif
  1051.  
  1052.     /* check first line of appts file to see if it is the new style */
  1053.     if ((appts = fopen(apts_pathname, "r")) != NULL) {
  1054.         fgets(buff, 80, appts);
  1055.         fclose(appts);
  1056.         if (!strcmp(buff, OHEADER) || !strncmp(buff, HEADER, 18)) {
  1057.             version2 = 1;
  1058.             one_based = 1;
  1059.         }
  1060. #ifdef CALENCHECK
  1061.         else
  1062.             err_rpt("wrong version appointments file format", FATAL);
  1063. #endif
  1064.     }
  1065.  
  1066. #ifndef CALENCHECK
  1067.     /* Convert from old format to new. There may some appts files
  1068.      * that are one-based, but are still old style. These are
  1069.      * also handled. (Note: for old-style one-based appts files
  1070.      * the user MUST start calentool with the -z flag.)
  1071.      */
  1072.      if (!version2)
  1073.         ver1to2();
  1074. #endif
  1075.     
  1076.     return(0);
  1077. }
  1078.  
  1079.