/* $Header$ * * This generates confirmation letters to people who recently set * their secure instance passwords. * * (c) Copyright 1992 by the Massachusetts Institute of Technology. * For copying and distribution information, please see the file * . */ #include #include #include #include #include #include #include #include #include EXEC SQL INCLUDE sqlca; #define LETTER "letter.template" extern int errno; char *whoami = "letter.gen"; main(argc, argv) int argc; char **argv; { FILE *out = stdout; char *outf = NULL, outft[64]; struct stat sb; int flag; struct timeval tv; EXEC SQL BEGIN DECLARE SECTION; char login[10], first[17], last[17], fullname[34], addr[84]; int lastrun, when; EXEC SQL END DECLARE SECTION; #ifsql INGRES EXEC SQL CONNECT moira; #endsql #ifsql INFORMIX EXEC SQL DATABASE moira; #endsql if (argc == 2) { if (stat(argv[1], &sb) == 0) { if (ModDiff (&flag, "users", sb.st_mtime)) exit(MR_DATE); if (flag < 0) { fprintf(stderr, "File %s does not need to be rebuilt.\n", argv[1]); exit(MR_NO_CHANGE); } } outf = argv[1]; sprintf(outft, "%s~", outf); if ((out = fopen(outft, "w")) == NULL) { fprintf(stderr, "unable to open %s for output\n", outf); exit(MR_OCONFIG); } } else if (argc != 1) { fprintf(stderr, "usage: %s [outfile]\n", argv[0]); exit(MR_ARGS); } else { outf = NULL; } init_letter(); /* The following is declarative, not executed, * and so is dependent on where it is in the file, * not in the order of execution of statements. */ EXEC SQL WHENEVER SQLERROR GOTO sqlerr; EXEC SQL SELECT secure INTO :lastrun FROM users WHERE users_id = 0; gettimeofday(&tv, NULL); EXEC SQL DECLARE x CURSOR FOR SELECT login, first, last, xaddress, secure FROM users WHERE secure > :lastrun; EXEC SQL OPEN x; while (1) { EXEC SQL FETCH x INTO :login, :first, :last, :addr, :when; if (sqlca.sqlcode != 0) break; strtrim(login); strtrim(first); strtrim(last); sprintf(fullname, "%s %s", first, last); print_letter(out, login, fullname, strtrim(addr), when); } EXEC SQL CLOSE x; lastrun = tv.tv_sec; EXEC SQL UPDATE users SET secure = :lastrun WHERE users_id = 0; #ifsql INGRES EXEC SQL DISCONNECT; #endsql #ifsql INFORMIX EXEC SQL CLOSE DATABASE; #endsql if (fclose(out)) { perror("close failed"); exit(MR_CCONFIG); } if (outf) fix_file(outf); exit(MR_SUCCESS); sqlerr: com_err(whoami, MR_INGRES_ERR, " code %d\n", sqlca.sqlcode); critical_alert("DCM", "Letter build encountered INGRES ERROR %d", sqlca.sqlcode); exit(MR_INGRES_ERR); } char *letter_text; /* Read the template into a buffer */ init_letter() { int fd; char filename[256]; struct stat stbuf; sprintf(filename, "%s/%s", DCM_DIR, LETTER); if ((fd = open(filename, O_RDONLY, 0)) < 0) { com_err(whoami, MR_OCONFIG, " opening letter template %s", filename); exit(MR_OCONFIG); } if (fstat(fd, &stbuf)) { com_err(whoami, MR_OCONFIG, " stating letter template %s", filename); exit(MR_OCONFIG); } if ((letter_text = (char *)malloc(stbuf.st_size + 1)) == NULL) { com_err(whoami, MR_NO_MEM, " reading letter template"); exit(MR_NO_MEM); } if (read(fd, letter_text, stbuf.st_size) < stbuf.st_size) { com_err(whoami, MR_OCONFIG, " unable to read all of letter"); exit(MR_OCONFIG); } letter_text[stbuf.st_size] = 0; close(fd); } /* Print out a copy of the letter */ print_letter(out, login, fullname, addr, when) FILE *out; char *login, *fullname, *addr; int when; { register char *p; char buf[256], *a1, *a2, *d; char *rindex(); /* split address into two lines. * First determine if postal or interdepartmental address. * Postal addreses end in state & zip code, as in "MA02139" * Anything else, assume interdepartmental. */ strcpy(buf, addr); a1 = buf; a2 = rindex(buf, ' '); /* before state & zip */ if (a2 && isupper(a2[1]) && isupper(a2[2]) && isdigit(a2[3]) && isdigit(a2[4]) && isdigit(a2[5]) && isdigit(a2[6]) && isdigit(a2[7])) { /* Must be postal address. */ /* missing space between state & zip, fix */ for (p = a2; *p; p++); /* find end of string */ for (p--; isdigit(*p); p--) p[2] = p[1]; p[2] = p[1]; p[1] = ' '; /* Backup to previous space, start of state */ for (; *a2 != ' '; a2--); /* Backup to previous space, start of city */ for (a2--; *a2 != ' '; a2--); /* terminate first line, leave a2 pointing at second */ *a2++ = 0; } else { /* Must be interdepartmental */ a2 = "MIT INTERDEPARTMENTAL MAIL"; } d = ctime(&when); d[strlen(d)-1] = 0; for (p = letter_text; *p; p++) { if (*p == '%') { p++; switch (*p) { case 'l': fputs(login, out); break; case 'n': fputs(fullname, out); break; case 'A': fputs(addr, out); break; case 'a': p++; switch (*p) { case '1': fputs(a1, out); break; case '2': fputs(a2, out); break; default: fputs(addr, out); } break; case 'd': fputs(d, out); break; default: putc('%', out); putc(*p, out); } } else putc(*p, out); } fflush(out); }