home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2109 < prev    next >
Encoding:
Internet Message Format  |  1990-12-28  |  38.2 KB

  1. From: dfs@doe.carleton.ca (David F. Skoll)
  2. Newsgroups: alt.sources
  3. Subject: REMIND 2.2 03/05
  4. Message-ID: <dfs.658781264@yar>
  5. Date: 16 Nov 90 18:47:44 GMT
  6.  
  7.  
  8. #!/bin/sh
  9. # This is part 03 of Remind-2.2
  10. if touch 2>&1 | fgrep 'amc' > /dev/null
  11.  then TOUCH=touch
  12.  else TOUCH=true
  13. fi
  14. # ============= main.c ==============
  15. if test X"$1" != X"-c" -a -f 'main.c'; then
  16.     echo "File already exists: skipping 'main.c'"
  17. else
  18. echo "x - extracting main.c (Text)"
  19. sed 's/^X//' << 'SHAR_EOF' > main.c &&
  20. X/***************************************************************/
  21. X/*                                                             */
  22. X/*  REMIND - version 2.2                                       */
  23. X/*                                                             */
  24. X/*  By David Skoll - 13 Novemeber 1990                         */
  25. X/*                                                             */
  26. X/*  (C) 1990 by David Skoll - all rights reserved              */
  27. X/*                                                             */
  28. X/***************************************************************/
  29. X
  30. X#include <stdio.h>
  31. X#include <string.h>
  32. X#include <ctype.h>
  33. X#ifndef UNIX
  34. X#include <stdlib.h>
  35. X#include <dos.h>
  36. X#include <stdarg.h>
  37. X#else
  38. X#include <varargs.h>
  39. X#include <sys/types.h>
  40. X#ifdef SYSV
  41. X#include <time.h>
  42. X#else
  43. X#include <sys/time.h>
  44. X#endif
  45. X#endif
  46. X#include "defines.h"
  47. X#include "protos.h"
  48. X
  49. X
  50. X/* List of months */
  51. Xchar *MonthName[] = {
  52. X   "January", "February", "March", "April", "May", "June",
  53. X   "July", "August", "September", "October", "November", "December"
  54. X};
  55. X
  56. X/* List of weekdays */
  57. Xchar *DayName[] = {
  58. X   "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"
  59. X};   
  60. X               
  61. X/* List of recognized tokens */
  62. X
  63. XToken keywd[] = {
  64. X   { "BANNER",    Banner_t, 0 },
  65. X   { "OMIT",      Omit_t,   0 },
  66. X   { "REM",       Rem_t,    0 },
  67. X   { "January",   Month_t,  0 },
  68. X   { "February",  Month_t,  1 },
  69. X   { "March",     Month_t,  2 },
  70. X   { "April",     Month_t,  3 },
  71. X   { "May",       Month_t,  4 },
  72. X   { "June",      Month_t,  5 },
  73. X   { "July",      Month_t,  6 },
  74. X   { "August",    Month_t,  7 },
  75. X   { "September", Month_t,  8 },
  76. X   { "October",   Month_t,  9 },
  77. X   { "November",  Month_t,  10 },
  78. X   { "December",  Month_t,  11 },
  79. X   { "Monday",    WkDay_t,  0  },
  80. X   { "Tuesday",   WkDay_t,  1  },
  81. X   { "Wednesday", WkDay_t,  2  },
  82. X   { "Thursday",  WkDay_t,  3  },
  83. X   { "Friday",    WkDay_t,  4  },
  84. X   { "Saturday",  WkDay_t,  5  },
  85. X   { "Sunday",    WkDay_t,  6  },
  86. X   { "MSG",       Msg_t,    0 },
  87. X   { "RUN",       Run_t,    0 },
  88. X   { "ONCE",      Once_t,   0 },
  89. X   { "INCLUDE",   Include_t, 0},
  90. X   { "AT",        At_t,      0}
  91. X};
  92. X
  93. X/* List of days in month - Feb MUST be 29 for CheckDate to work. */
  94. Xint MonthDays[] = {
  95. X   31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  96. X};
  97. X
  98. X/* Index of the first day of each month.  First array is non-leap-year;
  99. X   second is leap-year. */
  100. Xint MonthIndex[2][12] = {
  101. X   { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
  102. X   { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
  103. X};
  104. X
  105. X/* Global ommissions array */
  106. Xint FullOmitArray[FOMITSIZE];
  107. X
  108. X/* Global partial omissions array */
  109. Xint PartOmitArray[POMITSIZE];
  110. X
  111. X/* Define the working buffers */
  112. Xchar Line[512], WorkBuf[512];
  113. Xchar TmpBuf[512];
  114. Xint Fresh;  /* True if the contents of Line are fresh */
  115. X
  116. X/* Global variables */
  117. Xint Purge, Debug, Verbose, IgRun, IgOnce;
  118. Xint LastRun;
  119. Xchar FileName[200];
  120. Xint CurLine;
  121. Xchar Banner[200] = "Reminders for %w, %d%s %m, %y%o:";
  122. Xint NumEmitted, NumRem;
  123. Xint NumFullOmit, NumPartOmit;
  124. Xint JulianToday, RealToday;
  125. Xint CurYear, CurMon, CurDay;
  126. Xint QueueAts, PrintAts, NumAtsQueued;
  127. Xint Calendar, CalTime, CalWidth, SimpleCalendar;
  128. X
  129. Xstatic int JulFirst; /* Julian date of 1 Jan Current_year */
  130. Xstatic int FirstYear;
  131. X#ifndef UNIX
  132. Xint int_comp(int *a, int *b) { return *a - *b; }
  133. X#else
  134. Xint int_comp(a, b) 
  135. X   int *a;
  136. X   int *b;
  137. X{ return *a - *b; }
  138. X#endif
  139. X
  140. X/***************************************************************/
  141. X/*                                                             */
  142. X/* Output                                                      */
  143. X/* Output a string with line separators.                       */
  144. X/*                                                             */
  145. X/***************************************************************/
  146. X#ifndef UNIX
  147. Xvoid Output(char *s)
  148. X#else
  149. Xvoid Output(s)
  150. Xchar *s;
  151. X#endif
  152. X{
  153. X   while (*s) {
  154. X      if (*s == '\n') putchar('\\');
  155. X      putchar(*s++);
  156. X   }
  157. X   putchar('\n');
  158. X}
  159. X
  160. X/***************************************************************/
  161. X/*                                                             */
  162. X/*  int MoveBack(...)                                          */
  163. X/*                                                             */
  164. X/*  Move back by specified number of days, skipping holidays   */
  165. X/*                                                             */
  166. X/***************************************************************/
  167. X#ifndef UNIX
  168. Xint MoveBack (int jul, int back, int d, int m, int y, int omit)
  169. X#else
  170. Xint MoveBack (jul, back, d, m, y, omit)
  171. X     int jul;
  172. X     int back;
  173. X     int d;
  174. X     int m;
  175. X     int y;
  176. X     int omit;
  177. X#endif
  178. X{
  179. X   int temp;
  180. X
  181. X   if (!NumFullOmit && !NumPartOmit && !omit) return jul - back;
  182. X   while (back) {
  183. X      jul--;
  184. X      if (omit & 1 << (jul % 7)) continue; /* Omitted due to weekday */
  185. X
  186. X      /* Omit if in fully-specified omit list */
  187. X      if (NumFullOmit && bsearch(&jul, FullOmitArray, NumFullOmit, sizeof(int), int_comp)) continue;
  188. X
  189. X      if (NumPartOmit) {
  190. X     d--;
  191. X     if (d == 0) {
  192. X        m--;
  193. X        if (m < 0) {
  194. X           y--;
  195. X           m = 11;
  196. X        }
  197. X        d = DaysInMonth(m, y);
  198. X     }
  199. X     temp = (m << 5) + d;
  200. X     if (bsearch(&temp, PartOmitArray, NumPartOmit, sizeof(int), int_comp)) continue;
  201. X      }
  202. X      back--;
  203. X   }
  204. X   return jul;
  205. X}
  206. X
  207. X/***************************************************************/
  208. X/*                                                             */
  209. X/*  int ProcessLine()                                          */
  210. X/*                                                             */
  211. X/*  Process the line in the "Line" buffer.                     */
  212. X/*                                                             */
  213. X/*  Normally returns 0.  Returns 1 only if we're in Calendar   */
  214. X/*  mode and we hit a reminder which should be placed in the   */
  215. X/*  calendar.                                                  */
  216. X/*                                                             */
  217. X/***************************************************************/
  218. X#ifndef UNIX
  219. Xint ProcessLine(void)
  220. X#else
  221. Xint ProcessLine()
  222. X#endif
  223. X{
  224. X   char *s = Line;
  225. X   Token tok;
  226. X   int i;
  227. X
  228. X   while (isspace(*s)) s++;
  229. X
  230. X   /* Skip comments and blank lines */
  231. X   if (*s == '#' || *s == 0) {
  232. X      if (Purge && TopLevel()) Output(Line);
  233. X      return 0;
  234. X   }
  235. X
  236. X   tok = ParseToken(&s);
  237. X   switch(tok.type) {
  238. X      case Banner_t: DoBanner(&s);
  239. X             if (Purge && TopLevel()) Output(Line);
  240. X             break;
  241. X
  242. X      case Omit_t:   i = DoGlobalOmit(&s);
  243. X             if (Purge && TopLevel())
  244. X            if (i < 0) Eprint("Purged '%s'\n", Line);
  245. X            else       Output(Line);
  246. X             break;
  247. X
  248. X      case Rem_t:    i = DoRem(&s);
  249. X                 if (Calendar) return i;
  250. X             if (Purge && TopLevel())
  251. X            if (i < 0) Eprint("Purged '%s'\n", Line);
  252. X            else       Output(Line);
  253. X             NumRem++;
  254. X             break;
  255. X
  256. X      case Include_t: if (Purge && TopLevel()) Output(Line);
  257. X              DoInclude(&s);
  258. X              break;
  259. X               
  260. X
  261. X      default:       if (Purge && TopLevel()) Output(Line);
  262. X             Eprint("Unknown command '%s'\n", tok.str);
  263. X   }
  264. X   return 0;
  265. X}
  266. X
  267. X/***************************************************************/
  268. X/*                                                             */
  269. X#ifndef UNIX
  270. X/*  void Eprint(const char *f, ...)                            */
  271. X#else
  272. X/*  void Eprint(va_alist)                                      */
  273. X#endif
  274. X/*                                                             */
  275. X/*  Prints an error message.                                   */
  276. X/*                                                             */
  277. X/***************************************************************/
  278. X#ifndef UNIX
  279. Xvoid Eprint(const char *f, ...)
  280. X#else
  281. X/*VARARGS0*/
  282. Xvoid Eprint(va_alist)
  283. Xva_dcl
  284. X#endif
  285. X{
  286. X#ifndef UNIX
  287. X   va_list args;
  288. X#else
  289. X  va_list args;
  290. X  char *f;
  291. X#endif
  292. X
  293. X#ifndef UNIX
  294. X   if (Verbose & Fresh) {
  295. X#else
  296. X  if (Verbose & Fresh) {
  297. X#endif
  298. X      fprintf(stderr, "\n--- %s\n", Line);
  299. X      Fresh = 0;
  300. X   }
  301. X   if (Verbose) fprintf(stderr, "--- ");
  302. X   fprintf(stderr, "%s(%d): ", FileName, CurLine);
  303. X#ifndef UNIX
  304. X   va_start(args, f);
  305. X#else
  306. X   va_start(args);
  307. X   f = va_arg(args, char *);
  308. X#endif
  309. X   vfprintf(stderr, f, args);
  310. X#ifdef UNIX
  311. X   va_end(args);
  312. X#endif
  313. X}
  314. X
  315. X
  316. X/***************************************************************/
  317. X/*                                                             */
  318. X/*  int DoBanner(char **s)                                     */
  319. X/*                                                             */
  320. X/*  Sets the "Reminders for..." banner.                        */
  321. X/*                                                             */
  322. X/***************************************************************/
  323. X#ifndef UNIX
  324. Xint DoBanner(char **s)
  325. X#else
  326. Xint DoBanner(s)
  327. X     char **s;
  328. X#endif
  329. X{
  330. X   if (Purge) return 0;
  331. X   while (isspace(**s)) (*s)++;
  332. X   strcpy(Banner, *s);
  333. X   if (! *Banner)
  334. X   {
  335. X      if (Debug) Eprint("Empty banner.\n");
  336. X      strcpy(Banner, "Reminders for %w, %d%s %m, %y%o:");
  337. X   }
  338. X   if (NumRem && Debug) Eprint("Warning: Banner after reminder.\n");
  339. X   return 0;
  340. X}
  341. X
  342. X/***************************************************************/
  343. X/*                                                             */
  344. X/* int CheckDate(int d, int m, int y)                          */
  345. X/*                                                             */
  346. X/* Checks that a date is valid - returns 0 for OK, 1 for BAD.  */
  347. X/*                                                             */
  348. X/* If y=-1, just checks that month & day are valid, giving     */
  349. X/* benefit of the doubt for February 29.                       */
  350. X/*                                                             */
  351. X/* No point in checking if month is valid - months are named   */
  352. X/* and thus a month out of range can never be entered into     */
  353. X/* the system.                                                 */
  354. X/*                                                             */
  355. X/***************************************************************/
  356. X#ifndef UNIX
  357. Xint CheckDate(int d, int m, int y)
  358. X#else
  359. Xint CheckDate(d, m, y)
  360. X     int d;
  361. X     int m;
  362. X     int y;
  363. X#endif
  364. X{
  365. X   if (y == -1)
  366. X      if (d > 0 && d <= MonthDays[m]) return 0; else return 1;
  367. X   else
  368. X      if (y < BASE || y > BASE + 85) return 1;
  369. X      else if (d > 0 && d <= DaysInMonth(m, y)) return 0; else return 1;
  370. X}
  371. X
  372. X
  373. X/***************************************************************/
  374. X/*                                                             */
  375. X/*  int DoGlobalOmit(char **s)                                 */
  376. X/*                                                             */
  377. X/*  Add an entry to the global ommissions array.  Either       */
  378. X/*  a fully-specified date, or a mm-yy type date.              */
  379. X/*  Return 0 if OK, -1 if date is in past, 1 if problem.       */
  380. X/*                                                             */
  381. X/***************************************************************/
  382. X#ifndef UNIX
  383. Xint DoGlobalOmit(char **s)
  384. X#else
  385. Xint DoGlobalOmit(s)
  386. X     char **s;
  387. X#endif
  388. X{
  389. X   int d = -1, m = -1, y = -1;
  390. X   int omit;
  391. X   int *ptr;
  392. X   Token tok;
  393. X
  394. X   tok.type = Unknown_t;
  395. X   while(tok.type != Eol_t) {
  396. X      tok = ParseToken(s);
  397. X      switch (tok.type) {
  398. X     case Year_t:  y = tok.val; break;
  399. X     case Month_t: m = tok.val; break;
  400. X     case Day_t:   d = tok.val; break;
  401. X     case Eol_t:   break;
  402. X     default:      Eprint("Invalid token '%s' for OMIT command.\n", tok.str);
  403. X               return 1;
  404. X      }
  405. X   }
  406. X
  407. X   if (d == -1 || m == -1 || CheckDate(d, m, y)) {
  408. X      Eprint("Invalid date specification.\n");
  409. X      return 1;
  410. X   }
  411. X
  412. X   if (y == -1) { /* Only mm-dd specified */
  413. X      if (NumPartOmit == POMITSIZE) {
  414. X     Eprint("Too many partially-specified OMITs.\n");
  415. X     return 1;
  416. X      }
  417. X      omit = (m << 5) + d;
  418. X      ptr = PartOmitArray + NumPartOmit;
  419. X      NumPartOmit++;
  420. X      while (ptr > PartOmitArray && *(ptr-1) > omit) {
  421. X     *ptr = *(ptr-1);
  422. X     ptr--;
  423. X      }
  424. X      *ptr = omit;
  425. X
  426. X      /* Check if the bonehead already has it - if so, delete it */
  427. X      if (ptr > PartOmitArray && *(ptr-1) == *ptr) {
  428. X     if (Debug) Eprint("Duplicated partially-specified OMIT.\n");
  429. X     NumPartOmit--;
  430. X     while (ptr < NumPartOmit+PartOmitArray) {
  431. X        *ptr = *(ptr + 1);
  432. X        ptr++;
  433. X     }
  434. X      }
  435. X   } else { /* All three specified */
  436. X      if (NumFullOmit == FOMITSIZE) {
  437. X     Eprint("Too many fully-specified OMITs.\n");
  438. X     return 1;
  439. X      }
  440. X      omit = Julian(d, m, y);
  441. X      if (omit < JulianToday) {
  442. X     if (Debug) Eprint("Omit has expired.\n");
  443. X     return -1;
  444. X      }
  445. X
  446. X      ptr = FullOmitArray + NumFullOmit;
  447. X      NumFullOmit++;
  448. X      while (ptr > FullOmitArray && *(ptr-1) > omit) {
  449. X     *ptr = *(ptr-1);
  450. X     ptr--;
  451. X      }
  452. X      *ptr = omit;
  453. X
  454. X      /* Check if the bonehead already has it - if so, delete it */
  455. X      if (ptr > FullOmitArray && *(ptr-1) == *ptr) {
  456. X     if (Debug) Eprint("Duplicated fully-specified OMIT.\n");
  457. X     NumFullOmit--;
  458. X     while (ptr < NumFullOmit+FullOmitArray) {
  459. X        *ptr = *(ptr + 1);
  460. X        ptr++;
  461. X     }
  462. X      }
  463. X   }
  464. X   return 0;
  465. X}
  466. X
  467. X/***************************************************************/
  468. X/*                                                             */
  469. X/*  int strnicmp(char *s1, char*s1, int n)                     */
  470. X/*                                                             */
  471. X/*  Compares first n chars of string ignoring case.            */
  472. X/*                                                             */
  473. X/***************************************************************/
  474. X#ifndef UNIX
  475. Xint strncmpi(char *s1, char *s2, int n)
  476. X#else
  477. Xint strncmpi(s1, s2, n)
  478. X     char *s1;
  479. X     char *s2;
  480. X     int n;
  481. X#endif
  482. X{
  483. X   register int u1, u2;
  484. X   while (n)
  485. X   {
  486. X      if (!*s1 || !*s2) return upper(*s1) - upper(*s2);
  487. X      u1 = upper(*s1);
  488. X      u2 = upper(*s2);
  489. X      if (u1 != u2) return (u1 - u2);
  490. X      n--;
  491. X      s1++;
  492. X      s2++;
  493. X   }
  494. X   return 0;
  495. X}
  496. X
  497. X/***************************************************************/
  498. X/*                                                             */
  499. X/*  ParseToken(char **s);                                      */
  500. X/*                                                             */
  501. X/*  Parse the next token and adjust the character pointer.     */
  502. X/*                                                             */
  503. X/***************************************************************/
  504. X#ifndef UNIX
  505. XToken ParseToken(char **s)
  506. X#else
  507. XToken ParseToken(s)
  508. X     char **s;
  509. X#endif
  510. X{
  511. X
  512. X   Token tok;
  513. X   char *t = TmpBuf;
  514. X   int i, h, m;
  515. X   int len;
  516. X   char *colon = (char *) NULL;
  517. X
  518. X   *t = 0;
  519. X   tok.str = TmpBuf;
  520. X   
  521. X   /* Skip blank space */
  522. X   while (isspace(**s)) (*s)++;
  523. X
  524. X   /* End of line ? */
  525. X   if (**s == 0) {
  526. X      tok.type = Eol_t;
  527. X      tok.val = 0;
  528. X      return tok;
  529. X   }
  530. X
  531. X   /* Grab a space-delimited token */
  532. X   while (**s != 0 && !isspace(**s)) {
  533. X      *t++ = **s;
  534. X      (*s)++;
  535. X   }
  536. X   *t = 0;
  537. X   len = t - TmpBuf;
  538. X
  539. X   /* Check if it's a built-in token */
  540. X   for (i=0; i < sizeof(keywd)/sizeof(keywd[0]); i++)
  541. X      if (len >= 3 && !strncmpi(TmpBuf, keywd[i].str, len)) return keywd[i];
  542. X
  543. X   /* ARGH.  Check for "AT" as special case: < 3 chars */
  544. X   if (len == 2 && !strncmpi(TmpBuf, "AT", 2)) {
  545. X      tok.type = At_t;
  546. X      return tok;
  547. X   }
  548. X
  549. X   tok.type = Unknown_t;
  550. X
  551. X   /* If it's a comment, ignore the rest of the line */
  552. X   if (*(tok.str) == '#') {
  553. X      tok.type = Eol_t;
  554. X      return tok;
  555. X   }
  556. X
  557. X   /* Check if it's a number (optional +/-/* ahead of number */
  558. X   t = TmpBuf;
  559. X   if (isdigit(*t)) {
  560. X      while (*++t){
  561. X         if (*t == ':') {
  562. X            if (colon) return tok; else colon = t;
  563. X         } else if (!isdigit(*t)) return tok;
  564. X      }
  565. X   }
  566. X   else if (*t == '+' || *t == '-' || *t == '*') {
  567. X      if (!isdigit(*++t)) return tok;
  568. X      while (*++t) if (!isdigit(*t)) return tok;
  569. X   }
  570. X   else return tok;
  571. X
  572. X   /* OK, here we have a number - either a pure number, a delta, a time,
  573. X      back or a repeat marker */
  574. X
  575. X   if (colon) { /* got a time here */
  576. X      h = atoi(TmpBuf);
  577. X      m = atoi(colon + 1);
  578. X      if (h >= 0 && h <= 23 && m >= 0 && m <= 59) {
  579. X         tok.type = Time_t;
  580. X     tok.val = 60*h+m;
  581. X      }
  582. X      else return tok;
  583. X   }
  584. X   else if (*TmpBuf == '+') {
  585. X      tok.type = Delta_t;
  586. X      tok.val = atoi(TmpBuf + 1);
  587. X   }
  588. X   else if (*TmpBuf == '-') {
  589. X      tok.type = Back_t;
  590. X      tok.val = atoi(TmpBuf + 1);
  591. X   }
  592. X   else if (*TmpBuf == '*') {
  593. X      tok.type = Repeat_t;
  594. X      tok.val = atoi(TmpBuf + 1);
  595. X   }
  596. X   else {
  597. X      tok.val = atoi(TmpBuf);
  598. X      if (tok.val > 0 && tok.val <= 31) tok.type = Day_t;
  599. X      else if (tok.val >= 100) tok.type = Year_t;
  600. X      else {
  601. X     tok.type = Year_t;
  602. X     tok.val += 1900;
  603. X      }
  604. X   }
  605. X   return tok;
  606. X}
  607. X
  608. X/***************************************************************/
  609. X/*                                                             */
  610. X/*  int FromJulian(int jul, int *d, int *m, int *y)            */
  611. X/*                                                             */
  612. X/*  Convert a date from Julian to normal form.  Returns        */
  613. X/*  0 if conversion ok, -1 otherwise.                          */
  614. X/*                                                             */
  615. X/***************************************************************/
  616. X#ifndef UNIX
  617. Xint FromJulian(int jul, int *d, int *m, int *y)
  618. X#else
  619. Xint FromJulian(jul, d, m, y)
  620. X     int jul;
  621. X     int *d;
  622. X     int *m;
  623. X     int *y;
  624. X#endif
  625. X{
  626. X   int t;
  627. X
  628. X   if (jul < 0) return 1;
  629. X
  630. X   if (jul >= JulFirst && JulFirst != -1) {
  631. X      *y = FirstYear;
  632. X      jul -= JulFirst;
  633. X   } else *y = BASE;
  634. X
  635. X   *m = 0;
  636. X
  637. X   t = DaysInYear(*y);
  638. X   while (jul >= t) {
  639. X      jul -= t;
  640. X      (*y)++;
  641. X      t = DaysInYear(*y);
  642. X   }
  643. X
  644. X   t = DaysInMonth(*m, *y);
  645. X   while (jul >= t) {
  646. X      jul -= t;
  647. X      (*m)++;
  648. X      t = DaysInMonth(*m, *y);
  649. X   }
  650. X   *d = jul + 1;
  651. X   return 0;
  652. X}
  653. X
  654. X/***************************************************************/
  655. X/*                                                             */
  656. X/*  int Julian(d, m, y)                                        */
  657. X/*                                                             */
  658. X/*  Converts a date to the number of days after Jan 1 1990.    */
  659. X/*  Returns -1 if date is before Jan 1 1990.                   */
  660. X/*                                                             */
  661. X/***************************************************************/
  662. X#ifndef UNIX
  663. Xint Julian(int d, int m, int y)
  664. X#else
  665. Xint Julian(d, m, y)
  666. X     int d;
  667. X     int m;
  668. X     int y;
  669. X#endif
  670. X{
  671. X   int iy;
  672. X   int jul = 0;
  673. X
  674. X   if (y < BASE) return -1;
  675. X   if (JulFirst == -1 || y < FirstYear) 
  676. X      for (iy = BASE; iy < y; iy++) jul += DaysInYear(iy);
  677. X   else {
  678. X      jul = JulFirst;
  679. X      for (iy = FirstYear; iy < y; iy++) jul += DaysInYear(iy);
  680. X   }
  681. X      
  682. X   return jul + MonthIndex[IsLeapYear(y)][m] + d - 1;
  683. X}
  684. X
  685. X/***************************************************************/
  686. X/*                                                             */
  687. X/*  int FindTodaysDate(int *d, int *m, int *y)                 */
  688. X/*                                                             */
  689. X/*  Obtains today's date.  Returns Julian date or -1 for       */
  690. X/*  failure.                                                   */
  691. X/*                                                             */
  692. X/***************************************************************/
  693. X#ifndef UNIX
  694. Xint FindTodaysDate(int *d, int *m, int *y)
  695. X#else
  696. Xint FindTodaysDate(d, m, y)
  697. X     int *d;
  698. X     int *m;
  699. X     int *y;
  700. X#endif
  701. X{
  702. X#ifndef UNIX
  703. X   struct dosdate_t buf;
  704. X
  705. X   _dos_getdate(&buf);
  706. X
  707. X   *d = buf.day;
  708. X   *m = buf.month - 1;
  709. X   *y = buf.year;
  710. X#else
  711. X  time_t tloc;
  712. X  struct tm *t;
  713. X  
  714. X   (void) time(&tloc);
  715. X   t = localtime(&tloc);
  716. X       
  717. X   *d = t->tm_mday;
  718. X   *m = t->tm_mon;
  719. X   *y = t->tm_year + 1900;
  720. X   
  721. X#endif
  722. X   if (CheckDate(*d, *m, *y)) return -1;
  723. X   return Julian(*d, *m, *y);
  724. X}
  725. X
  726. X#ifndef UNIX
  727. Xint main(int argc, char *argv[])
  728. X#else
  729. Xint main(argc, argv)
  730. X     int argc;
  731. X     char *argv[];
  732. X#endif
  733. X{
  734. X#ifdef UNIX
  735. X#ifdef SYSV
  736. X   pid_t pid;
  737. X#else
  738. X   int pid;
  739. X#endif
  740. X#endif
  741. X
  742. X   NumEmitted = 0;
  743. X   NumRem = 0;
  744. X   JulFirst = -1;  /* Initialize JulFirst so it's not used by Julian */
  745. X      
  746. X   JulianToday = FindTodaysDate(&CurDay, &CurMon, &CurYear);
  747. X   if (JulianToday < 0) {
  748. X      fprintf(stderr, "remind: System date is illegal - Ensure that year is at least %d.\n", BASE);
  749. X      return 1;
  750. X   }
  751. X   
  752. X   RealToday = JulianToday;
  753. X   
  754. X   initialize(argc, argv);
  755. X
  756. X   FirstYear = CurYear;
  757. X   JulFirst = Julian(1, 0, CurYear);  /* Do expensive computation once */
  758. X   FirstYear = CurYear;
  759. X
  760. X   if (Calendar) {
  761. X      DoCalendar();
  762. X      return 0;
  763. X   }
  764. X   while (1) {
  765. X      if (ReadLine()) break;
  766. X      ProcessLine();
  767. X   }
  768. X   if (NumEmitted == 0 && NumAtsQueued == 0 && !Purge && !Debug) 
  769. X       printf("No reminders.\n");
  770. X#ifdef UNIX
  771. X   if (NumEmitted == 0 && NumAtsQueued != 0 && !Purge && !Debug)
  772. X       printf("%d reminder%s queued for later today.\n", NumAtsQueued,
  773. X              (NumAtsQueued == 1) ? "" : "s");
  774. X
  775. X   if (NumAtsQueued) {
  776. X      pid = fork();
  777. X      if (pid == -1) Eprint("Can't fork to perform ATs!\n");
  778. X      if (pid != 0) return 0;
  779. X      HandleQueuedAts();
  780. X   }
  781. X#endif
  782. X}
  783. X/***************************************************************/
  784. X/*                                                             */
  785. X/* SystemTime                                                  */
  786. X/*                                                             */
  787. X/* Returns current system time in seconds past midnight.       */
  788. X/*                                                             */
  789. X/***************************************************************/
  790. X#ifndef UNIX
  791. Xlong SystemTime(void)
  792. X#else
  793. Xlong SystemTime()
  794. X#endif
  795. X{
  796. X#ifdef UNIX
  797. X  time_t tloc;
  798. X  struct tm *t;
  799. X  
  800. X   (void) time(&tloc);
  801. X   t = localtime(&tloc);
  802. X   return (long) t->tm_hour * 3600L + (long) t->tm_min * 60L + (long) t->tm_sec;
  803. X
  804. X#else
  805. X   struct dostime_t tloc;
  806. X   _dos_gettime(&tloc);
  807. X   return (long) tloc.hour * 3600L + (long) tloc.minute * 60L + (long) tloc.second;
  808. X#endif
  809. X}
  810. SHAR_EOF
  811. $TOUCH -am 1115165290 main.c &&
  812. chmod 0600 main.c ||
  813. echo "restore of main.c failed"
  814. set `wc -c main.c`;Wc_c=$1
  815. if test "$Wc_c" != "21719"; then
  816.     echo original size 21719, current size $Wc_c
  817. fi
  818. fi
  819. # ============= nextdate.c ==============
  820. if test X"$1" != X"-c" -a -f 'nextdate.c'; then
  821.     echo "File already exists: skipping 'nextdate.c'"
  822. else
  823. echo "x - extracting nextdate.c (Text)"
  824. sed 's/^X//' << 'SHAR_EOF' > nextdate.c &&
  825. X#include "defines.h"
  826. X#include "globals.h"
  827. X#include "protos.h"
  828. X
  829. X/***************************************************************/
  830. X/*                                                             */
  831. X/*  int TryNextDate(int *retday, int *retmon, int *retyr,      */
  832. X/*                  int startday, int startmon, int startyr,   */
  833. X/*                  int conday, int conmon, int conyr,         */
  834. X/*                  int wkday, int cons, int inc)              */
  835. X/*                                                             */
  836. X/*  This function tries to find the next date satisfying       */
  837. X/*  the given constraints.  Returns                            */
  838. X/*  0 for success.  Returns non-zero if a constraint would     */
  839. X/*  be violated.  Note that if DAY and WEEKDAY are both        */
  840. X/*  constrained, then MONTH and YEAR may be violated.          */
  841. X/*  Otherwise, all constraints are honoured.                   */
  842. X/*  The starting point for the search is thisday, etc.         */
  843. X/*                                                             */
  844. X/*  If inc is non-zero, then the search begins from the day    */
  845. X/*  after the specified date.  Note that this function assumes */
  846. X/*  that the given date is valid.                              */
  847. X/*                                                             */
  848. X/***************************************************************/
  849. X#ifndef UNIX
  850. Xint TryNextDate(int *retday, int *retmon, int *retyr,
  851. X        int d, int m, int y,
  852. X        int conday, int conmon, int conyr,
  853. X        int wkday, int cons, int inc)
  854. X#else
  855. Xint TryNextDate(retday, retmon, retyr, d, m, y, conday, conmon, conyr,
  856. X                wkday, cons, inc)
  857. X     int *retday, *retmon, *retyr, d, m, y, conday, conmon, conyr, wkday, cons, inc;
  858. X     
  859. X#endif
  860. X
  861. X{
  862. X   int jul, jul2;
  863. X   int dd = d, mm = m, yy = y;
  864. X
  865. X   if (inc)
  866. X   {
  867. X      d++;
  868. X      if (d > DaysInMonth(m, y)) {
  869. X     m++; d = 1;
  870. X     if (m > 11) {
  871. X        y++; m = 0;
  872. X     }
  873. X      }
  874. X   }
  875. X
  876. X
  877. X   switch (cons & 15) {
  878. X
  879. X      case 0:  /* No constraints - just use the start date */
  880. X     *retday = d;
  881. X     *retmon = m;
  882. X     *retyr  = y;
  883. X     return 0;
  884. X
  885. X      case 1: /* Day constrained to be d */
  886. X     *retday = conday;
  887. X     if (d > conday) {
  888. X        m++;
  889. X        if (m > 11) {y++; m=0;}
  890. X     }
  891. X     while (conday > DaysInMonth(m, y)) {
  892. X        m++;
  893. X        if (m > 11) {y++; m=0;}
  894. X     }
  895. X     *retmon = m;
  896. X     *retyr = y;
  897. X     return 0;
  898. X
  899. X      case 2: /* Month constrained to be m */
  900. X     *retmon = conmon;
  901. X     if (m > conmon) {y++; d = 1;}
  902. X     else if (m < conmon) d = 1;
  903. X     *retday = d;
  904. X     *retyr = y;
  905. X     return 0;
  906. X
  907. X      case 3: /* Month and day constrained */
  908. X     *retmon = conmon;
  909. X     *retday = conday;
  910. X     if (m > conmon || (m == conmon && d > conday)) y++;
  911. X     while (conday > DaysInMonth(conmon, y)) y++;
  912. X     *retyr = y;
  913. X     return 0;
  914. X
  915. X      case 4: /* Year alone constrained */
  916. X     if (y > conyr) return 1;
  917. X     *retyr = conyr;
  918. X     if (y < conyr) {
  919. X        *retmon = 0;
  920. X        *retday = 1;
  921. X     }
  922. X     else {
  923. X        *retmon = m;
  924. X        *retday = d;
  925. X     }
  926. X     return 0;
  927. X
  928. X      case 5: /* Year and day constrained */
  929. X     if (y > conyr) return 1;
  930. X     *retyr = conyr;
  931. X     *retday = conday;
  932. X     if (y < conyr) {
  933. X        *retmon = 0;
  934. X        return 0;
  935. X     }
  936. X     if (d > conday) {
  937. X       m++;
  938. X       if (m > 11) return 1;
  939. X     }
  940. X     while (conday > DaysInMonth(m, y)) {
  941. X        m++;
  942. X        if (m > 11) return 1;
  943. X     }
  944. X     *retmon = m;
  945. X     return 0;
  946. X
  947. X      case 6: /* Year and month constrained */
  948. X     if (y > conyr || (y == conyr && m > conmon)) return 1;
  949. X     *retyr = conyr;
  950. X     *retmon = conmon;
  951. X     if (y < conyr || (y == conyr && m < conmon)) {
  952. X        *retday = 1;
  953. X        return 0;
  954. X     }
  955. X     *retday = d;
  956. X     return 0;
  957. X
  958. X      case 7: /* Year, month and day constrained */
  959. X     *retday = conday;
  960. X     *retmon = conmon;
  961. X     *retyr = conyr;
  962. X     if (y > conyr || (y == conyr && m > conmon) ||
  963. X         (y == conyr && m == conmon && d > conday)) return 1;
  964. X     return 0;
  965. X
  966. X      case 8: /* Only the weekday constrained.  Let's go to Julian mode */
  967. X     jul = Julian(d, m, y);
  968. X     while (!(wkday & (1 << (jul % 7)))) jul++;
  969. X     FromJulian(jul, retday, retmon, retyr);
  970. X     return 0;
  971. X
  972. X      case 9: /* GASP! day and weekday constrained .. bleah! */
  973. X     /* First, try last month. */
  974. X     jul2 = Julian(d, m, y);
  975. X     if (m != 0 || y != BASE)
  976. X     {
  977. X        mm--;
  978. X        if (mm < 0) {yy--; mm = 11;}
  979. X
  980. X        /* If there are fewer days in month than required, it
  981. X           can't possibly match.  */
  982. X        if (conday <= DaysInMonth(mm, yy)) {
  983. X           jul = Julian(conday, mm, yy);
  984. X           while (!(wkday & (1 << (jul % 7)))) jul++;
  985. X           if (jul >= jul2) { /* SUCCESS! */
  986. X          FromJulian(jul, retday, retmon, retyr);
  987. X          return 0;
  988. X           }
  989. X        }
  990. X     }
  991. X     /* Didn't work - try this month */
  992. X     if (conday <= DaysInMonth(m, y)) {
  993. X        jul = Julian(conday, m, y);
  994. X        while (!(wkday & (1 << (jul % 7)))) jul++;
  995. X        if (jul >= jul2) { /* SUCCESS! */
  996. X           FromJulian(jul, retday, retmon, retyr);
  997. X           return 0;
  998. X        }
  999. X     }
  1000. X     /* Argh!  Try next available month */
  1001. X     mm = m;
  1002. X     yy = y;
  1003. X     do {
  1004. X        mm++;
  1005. X        if (mm > 11) {mm = 0; yy++;}
  1006. X     } while (conday > DaysInMonth(mm, yy));
  1007. X     jul = Julian(conday, mm, yy);
  1008. X     while (!(wkday & (1 << (jul % 7)))) jul++;
  1009. X     FromJulian(jul, retday, retmon, retyr);
  1010. X     return 0;
  1011. X
  1012. X      case 10: /* Month and Weekday constrained */
  1013. X     if (m < conmon) {
  1014. X        jul = Julian(1, conmon, y);
  1015. X        while (!(wkday & (1 << (jul % 7)))) jul++;
  1016. X        FromJulian(jul, retday, retmon, retyr);
  1017. X        return 0;
  1018. X     } else if (m == conmon) {
  1019. X        jul = Julian(d, conmon, y);
  1020. X        while (!(wkday & (1 << (jul % 7)))) jul++;
  1021. X        FromJulian(jul, retday, retmon, retyr);
  1022. X        if (*retmon != conmon) {
  1023. X           jul = Julian(1, conmon, y+1);
  1024. X           while (!(wkday & (1 << (jul % 7)))) jul++;
  1025. X           FromJulian(jul, retday, retmon, retyr);
  1026. X        }
  1027. X        return 0;
  1028. X     } else { /* m > conmon */
  1029. X        jul = Julian(1, conmon, y+1);
  1030. X        while (!(wkday & (1 << (jul % 7)))) jul++;
  1031. X        FromJulian(jul, retday, retmon, retyr);
  1032. X        return 0;
  1033. X     }
  1034. X
  1035. X      case 11: /* Day, Month and Weekday constrained */
  1036. X     jul2 = Julian(d, m, y);
  1037. X
  1038. X     /* Blip up to next valid year */
  1039. X     while (conday > DaysInMonth(m, y)) y++;
  1040. X
  1041. X     /* Try this year */
  1042. X     jul = Julian(conday, conmon, y);
  1043. X     while (!(wkday & (1 << (jul % 7)))) jul++;
  1044. X     if (jul >= jul2) {
  1045. X        FromJulian(jul, retday, retmon, retyr);
  1046. X        return 0;
  1047. X     }
  1048. X
  1049. X     /* Must be next year */
  1050. X     jul = Julian(conday, conmon, y+1);
  1051. X     while (!(wkday & (1 << (jul % 7)))) jul++;
  1052. X     FromJulian(jul, retday, retmon, retyr);
  1053. X     return 0;
  1054. X
  1055. X      case 12: /* Weekday and year specified */
  1056. X     if (y > conyr) return 1;
  1057. X     if (y == conyr) {mm = m; dd = d;} else {mm = 0; dd = 1;}
  1058. X     jul = Julian(dd, mm, conyr);
  1059. X     while (!(wkday & (1 << (jul % 7)))) jul++;
  1060. X     FromJulian(jul, retday, retmon, retyr);
  1061. X     return 0;
  1062. X
  1063. X      case 13: /* Weekday, year and day specified */
  1064. X     if (y > conyr+1 || (y > conyr && m>0)) return 1;
  1065. X     jul2 = Julian(d, m, y);
  1066. X     if (y > conyr ) {
  1067. X        jul = Julian(conday, 11, conyr);
  1068. X        while (!(wkday & (1 << (jul % 7)))) jul++;
  1069. X        if (jul >= jul2) {
  1070. X           FromJulian(jul, retday, retmon, retyr);
  1071. X           return 0;
  1072. X        }
  1073. X     } else if (y < conyr) {
  1074. X        jul = Julian(conday, 0, conyr);
  1075. X        while (!(wkday & (1 << (jul % 7)))) jul++;
  1076. X        FromJulian(jul, retday, retmon, retyr);
  1077. X        return 0;
  1078. X     }
  1079. X     else {
  1080. X        /* Try last month */
  1081. X        if (m > 0) {
  1082. X           mm = m - 1;
  1083. X           while (conday > DaysInMonth(mm, y)) mm--;
  1084. X           jul = Julian(conday, mm, y);
  1085. X           while (!(wkday & (1 << (jul % 7)))) jul++;
  1086. X           if (jul >= jul2) {
  1087. X          FromJulian(jul, retday, retmon, retyr);
  1088. X          return 0;
  1089. X           }
  1090. X        }
  1091. X        /* Try this month */
  1092. X        if (conday <= DaysInMonth(m,y)) {
  1093. X           jul = Julian(conday, m, y);
  1094. X           while (!(wkday & (1 << (jul % 7)))) jul++;
  1095. X           if (jul >= jul2) {
  1096. X          FromJulian(jul, retday, retmon, retyr);
  1097. X          return 0;
  1098. X           }
  1099. X        }
  1100. X        /* Try next month */
  1101. X        if (m == 11) return 1;
  1102. X        m++;
  1103. X        while (conday > DaysInMonth(m, y)) m++;
  1104. X        jul = Julian(conday, m, y);
  1105. X        while (!(wkday & (1 << (jul % 7)))) jul++;
  1106. X        FromJulian(jul, retday, retmon, retyr);
  1107. X        return 0;
  1108. X     }
  1109. X
  1110. X      case 14:  /* Weekday, Month and Year specified */
  1111. X     if (y > conyr || (y == conyr && m > conmon)) return 1;
  1112. X     if (conyr > y || (conyr == y && conmon > m)) {
  1113. X        jul = Julian(1, conmon, conyr);
  1114. X        while (!(wkday & (1 << (jul % 7)))) jul++;
  1115. X        FromJulian(jul, retday, retmon, retyr);
  1116. X        return 0;
  1117. X     } else {
  1118. X        jul = Julian(d, m, y);
  1119. X        while (!(wkday & (1 << (jul % 7)))) jul++;
  1120. X        FromJulian(jul, retday, retmon, retyr);
  1121. X        if (*retmon == conmon) return 0; else return 1;
  1122. X
  1123. X     }
  1124. X
  1125. X      case 15: /* Weekday, day, month and year specified */
  1126. X     jul2 = Julian(d, m, y);
  1127. X     jul = Julian(conday, conmon, conyr);
  1128. X     while (!(wkday & (1 << (jul % 7)))) jul++;
  1129. X     FromJulian(jul, retday, retmon, retyr);
  1130. X     if (jul < jul2) return 1;
  1131. X     return 0;
  1132. X   }
  1133. X}
  1134. SHAR_EOF
  1135. $TOUCH -am 1115093690 nextdate.c &&
  1136. chmod 0600 nextdate.c ||
  1137. echo "restore of nextdate.c failed"
  1138. set `wc -c nextdate.c`;Wc_c=$1
  1139. if test "$Wc_c" != "8637"; then
  1140.     echo original size 8637, current size $Wc_c
  1141. fi
  1142. fi
  1143. # ============= protos.h ==============
  1144. if test X"$1" != X"-c" -a -f 'protos.h'; then
  1145.     echo "File already exists: skipping 'protos.h'"
  1146. else
  1147. echo "x - extracting protos.h (Text)"
  1148. sed 's/^X//' << 'SHAR_EOF' > protos.h &&
  1149. X
  1150. X/* Function Prototypes go here */
  1151. X
  1152. X#ifndef UNIX
  1153. Xint   CheckDate   (int d,   int m,  int y);
  1154. Xint   DoBanner    (char **s);
  1155. Xvoid  DoCalendar  (void);
  1156. Xint   DoGlobalOmit(char **s);
  1157. Xvoid  DoInclude   (char **s);
  1158. Xint   DoRem       (char **s);
  1159. Xint   DoSubst     (char *src, char *dst, int d, int m, int y, int jul, enum Token_t t, int tim);
  1160. Xvoid  Eprint(const char *f, ...);
  1161. Xint   FindTodaysDate(int *d, int *m, int *y);
  1162. Xint   FromJulian  (int jul, int *d, int *m, int *y);
  1163. Xint   GetTriggerDate (int d, int m, int y, int wd, int cons, int back, int repeat, int omit);
  1164. Xvoid  HandleQueuedAts(void);
  1165. Xvoid  initialize  (int argc, char *argv[]);
  1166. Xint   int_comp    (int *, int *);
  1167. Xint   Julian      (int d,   int m,  int y);
  1168. Xint   MoveBack    (int jul, int back, int d, int m, int y, int omit);
  1169. Xvoid  OpenFile    (char *s);
  1170. Xvoid  Output      (char *s);
  1171. XToken ParseToken  (char **s);
  1172. Xint   ProcessLine (void);
  1173. Xint   ReadLine    (void);
  1174. Xlong  SystemTime  (void);
  1175. Xint   TopLevel    (void);
  1176. Xint   TryNextDate(int *retday, int *retmon, int *retyr,
  1177. X          int startday, int startmon, int startyr,
  1178. X          int conday, int conmon, int conyr,
  1179. X          int wkday, int cons, int inc);
  1180. X#else
  1181. Xint   CheckDate   ();
  1182. Xint   DoBanner    ();
  1183. Xvoid  DoCalendar  ();
  1184. Xint   DoGlobalOmit();
  1185. Xvoid  DoInclude   ();
  1186. Xint   DoRem       ();
  1187. Xint   DoSubst     ();
  1188. Xvoid  Eprint();
  1189. Xint   FindTodaysDate();
  1190. Xint   FromJulian  ();
  1191. Xint   GetTriggerDate();
  1192. Xvoid  HandleQueuedAts();
  1193. Xvoid  initialize  ();
  1194. Xint   int_comp    ();
  1195. Xint   Julian      ();
  1196. Xint   MoveBack    ();
  1197. Xvoid  OpenFile    ();
  1198. Xvoid  Output      ();
  1199. XToken ParseToken  ();
  1200. Xint   ProcessLine ();
  1201. Xint   ReadLine    ();
  1202. Xvoid  SigHupHandler();
  1203. Xlong  SystemTime  ();
  1204. Xint   TopLevel    ();
  1205. Xint   TryNextDate ();
  1206. X#endif
  1207. X
  1208. SHAR_EOF
  1209. $TOUCH -am 1115095890 protos.h &&
  1210. chmod 0600 protos.h ||
  1211. echo "restore of protos.h failed"
  1212. set `wc -c protos.h`;Wc_c=$1
  1213. if test "$Wc_c" != "1717"; then
  1214.     echo original size 1717, current size $Wc_c
  1215. fi
  1216. fi
  1217. # ============= remind-all.csh ==============
  1218. if test X"$1" != X"-c" -a -f 'remind-all.csh'; then
  1219.     echo "File already exists: skipping 'remind-all.csh'"
  1220. else
  1221. echo "x - extracting remind-all.csh (Text)"
  1222. sed 's/^X//' << 'SHAR_EOF' > remind-all.csh &&
  1223. X#!/bin/csh -f
  1224. X
  1225. X# Shell script to mail all users reminders.
  1226. X
  1227. X# Run it AFTER MIDNIGHT so that date is correct!
  1228. X# On our system, we have the following in our crontab:
  1229. X# 05 5 * * * /usr/share/lib/remind/remind-all > /dev/null 2>&1
  1230. X
  1231. X# Also, you MUST use the -r and -q options on REMIND, otherwise SEVERE
  1232. X# security hole could develop.  I recommend making this script
  1233. X# readable and executable only by root to minimize security problems.
  1234. X# DO NOT make the script setuid!
  1235. X
  1236. X# The following line gets a list of users for systems using SUN's
  1237. X# NIS service:
  1238. Xset USERS  = `ypcat passwd | awk -F: '{print $1}'`
  1239. X
  1240. X# The following line gets a list of users by examining /etc/passwd:
  1241. X# set USERS = `awk -F: '{print $1}' /etc/passwd`
  1242. X
  1243. X# If neither of the above methods works, you must come up with some
  1244. X# way of getting a list of users on the system
  1245. X
  1246. X# Set the following variables as appropriate for your system
  1247. Xset REMIND = /usr/local/bin/remind
  1248. Xset MAIL   = /usr/ucb/mail
  1249. Xset CMP    = /usr/bin/cmp
  1250. Xset RM     = "/usr/bin/rm -f"
  1251. X
  1252. Xset EMPTY  = /tmp/Empty.$$
  1253. Xset FULL   = /tmp/Full.$$
  1254. X
  1255. X# Create the dummy empty reminder file
  1256. X$REMIND -rq /dev/null > $EMPTY
  1257. X
  1258. X# Scan each user's directory for a .reminders file
  1259. Xforeach i ($USERS)
  1260. X   if (-r ~$i/.reminders) then
  1261. X
  1262. X#     echo "$i has a .reminders file."     DEBUGGING PURPOSES ONLY
  1263. X
  1264. X      $REMIND -rq ~$i/.reminders > $FULL
  1265. X      $CMP -s $EMPTY $FULL
  1266. X      if ($status != 0) then
  1267. X
  1268. X#        echo "Sending mail to $i"         DEBUGGING PURPOSES ONLY
  1269. X
  1270. X         $MAIL -s "Reminders" $i < $FULL
  1271. X      endif
  1272. X      $RM $FULL
  1273. X   endif
  1274. Xend
  1275. X
  1276. X$RM $EMPTY
  1277. SHAR_EOF
  1278. $TOUCH -am 1113132790 remind-all.csh &&
  1279. chmod 0700 remind-all.csh ||
  1280. echo "restore of remind-all.csh failed"
  1281. set `wc -c remind-all.csh`;Wc_c=$1
  1282. if test "$Wc_c" != "1568"; then
  1283.     echo original size 1568, current size $Wc_c
  1284. fi
  1285. fi
  1286. # ============= remind-all.sh ==============
  1287. if test X"$1" != X"-c" -a -f 'remind-all.sh'; then
  1288.     echo "File already exists: skipping 'remind-all.sh'"
  1289. else
  1290. echo "x - extracting remind-all.sh (Text)"
  1291. sed 's/^X//' << 'SHAR_EOF' > remind-all.sh &&
  1292. X# Shell script to mail all users reminders.
  1293. X
  1294. X# Thanks to Bill Aten for this script.
  1295. X
  1296. X# Run it AFTER MIDNIGHT so that date is correct!
  1297. X# On our system, we have the following in our crontab:
  1298. X# 02 00 * * * /usr/local/adm/remind-all >/dev/null 2>&1
  1299. X
  1300. X# Also, you MUST use the -r and -q options on REMIND, otherwise a SEVERE
  1301. X# security hole could develop.  I recommend making this script
  1302. X# readable and executable only by root to minimize security problems.
  1303. X# DO NOT make the script setuid!
  1304. X
  1305. X# The following line gets a list of users for systems using SUN's
  1306. X# NIS service:
  1307. X# USERS=`ypcat passwd | awk -F: '{print $1}'`
  1308. X
  1309. X# The following line gets a list of users by examining /etc/passwd:
  1310. XUSERS=`awk -F: '{print $1}' /etc/passwd`
  1311. X
  1312. X# If neither of the above methods works, you must come up with some
  1313. X# way of getting a list of users on the system
  1314. X
  1315. X# Set the following variables as appropriate for your system
  1316. XREMIND=/usr/local/bin/remind
  1317. XMAIL=/usr/bin/mail
  1318. XCMP=/bin/cmp
  1319. XRM="/bin/rm -f"
  1320. X
  1321. XEMPTY=/tmp/Empty.$$
  1322. XFULL=/tmp/Full.$$
  1323. X
  1324. X# Create the dummy empty reminder file
  1325. X$REMIND -rq /dev/null > $EMPTY
  1326. X
  1327. X# Scan each user's directory for a .reminders file
  1328. Xfor i in $USERS
  1329. Xdo
  1330. XHOME=`grep \^$i: /etc/passwd | awk -F: '{print $6}'`
  1331. X   if [ -r $HOME/.reminders ]; then
  1332. X
  1333. X#     echo "$i has a .reminders file."     DEBUGGING PURPOSES ONLY
  1334. X
  1335. X      $REMIND -rq $HOME/.reminders > $FULL
  1336. X      if `$CMP -s $EMPTY $FULL`; then
  1337. X         : do nothing
  1338. X      else
  1339. X
  1340. X#        echo "Sending mail to $i"         DEBUGGING PURPOSES ONLY
  1341. X
  1342. X         $MAIL -s "Reminders" $i < $FULL
  1343. X      fi
  1344. X      $RM $FULL
  1345. X   fi
  1346. Xdone
  1347. X
  1348. X$RM $EMPTY
  1349. SHAR_EOF
  1350. $TOUCH -am 1116131490 remind-all.sh &&
  1351. chmod 0700 remind-all.sh ||
  1352. echo "restore of remind-all.sh failed"
  1353. set `wc -c remind-all.sh`;Wc_c=$1
  1354. if test "$Wc_c" != "1589"; then
  1355.     echo original size 1589, current size $Wc_c
  1356. fi
  1357. fi
  1358. echo "End of part 3, continue with part 4"
  1359. exit 0
  1360.