[12454] | 1 | |
---|
| 2 | /* |
---|
| 3 | * rcvtty.c -- a rcvmail program (a lot like rcvalert) handling IPC ttys |
---|
| 4 | * |
---|
| 5 | * $Id: rcvtty.c,v 1.1.1.1 1999-02-07 18:14:16 danw Exp $ |
---|
| 6 | */ |
---|
| 7 | |
---|
| 8 | #include <h/mh.h> |
---|
| 9 | #include <h/signals.h> |
---|
| 10 | #include <h/rcvmail.h> |
---|
| 11 | #include <h/scansbr.h> |
---|
| 12 | #include <zotnet/tws/tws.h> |
---|
| 13 | #include <signal.h> |
---|
| 14 | #include <fcntl.h> |
---|
| 15 | |
---|
| 16 | #include <utmp.h> |
---|
| 17 | #ifndef UTMP_FILE |
---|
| 18 | # ifdef _PATH_UTMP |
---|
| 19 | # define UTMP_FILE _PATH_UTMP |
---|
| 20 | # else |
---|
| 21 | # define UTMP_FILE "/etc/utmp" |
---|
| 22 | # endif |
---|
| 23 | #endif |
---|
| 24 | |
---|
| 25 | #define SCANFMT \ |
---|
| 26 | "%2(hour{dtimenow}):%02(min{dtimenow}): %<(size)%5(size) %>%<{encrypted}E%>\ |
---|
| 27 | %<(mymbox{from})%<{to}To:%14(friendly{to})%>%>%<(zero)%17(friendly{from})%> \ |
---|
| 28 | %{subject}%<{body}<<%{body}>>%>" |
---|
| 29 | |
---|
| 30 | static struct swit switches[] = { |
---|
| 31 | #define BIFFSW 0 |
---|
| 32 | { "biff", 0 }, |
---|
| 33 | #define FORMSW 1 |
---|
| 34 | { "form formatfile", 0 }, |
---|
| 35 | #define FMTSW 2 |
---|
| 36 | { "format string", 5 }, |
---|
| 37 | #define WIDTHSW 3 |
---|
| 38 | { "width columns", 0 }, |
---|
| 39 | #define NLSW 4 |
---|
| 40 | { "newline", 0 }, |
---|
| 41 | #define NNLSW 5 |
---|
| 42 | { "nonewline", 0 }, |
---|
| 43 | #define BELSW 6 |
---|
| 44 | { "bell", 0 }, |
---|
| 45 | #define NBELSW 7 |
---|
| 46 | { "nobell", 0 }, |
---|
| 47 | #define VERSIONSW 8 |
---|
| 48 | { "version", 0 }, |
---|
| 49 | #define HELPSW 9 |
---|
| 50 | { "help", 4 }, |
---|
| 51 | { NULL, 0 } |
---|
| 52 | }; |
---|
| 53 | |
---|
| 54 | static jmp_buf myctx; |
---|
| 55 | static int bell = 1; |
---|
| 56 | static int newline = 1; |
---|
| 57 | static int biff = 0; |
---|
| 58 | static int width = 0; |
---|
| 59 | static char *form = NULL; |
---|
| 60 | static char *format = NULL; |
---|
| 61 | |
---|
| 62 | /* |
---|
| 63 | * external prototypes |
---|
| 64 | */ |
---|
| 65 | char *getusername(void); |
---|
| 66 | |
---|
| 67 | /* |
---|
| 68 | * static prototypes |
---|
| 69 | */ |
---|
| 70 | static RETSIGTYPE alrmser (int); |
---|
| 71 | static int message_fd (char **); |
---|
| 72 | static int header_fd (void); |
---|
| 73 | static void alert (char *, int); |
---|
| 74 | |
---|
| 75 | |
---|
| 76 | int |
---|
| 77 | main (int argc, char **argv) |
---|
| 78 | { |
---|
| 79 | int md, vecp = 0; |
---|
| 80 | char *cp, *user, buf[BUFSIZ], tty[BUFSIZ]; |
---|
| 81 | char **argp, **arguments, *vec[MAXARGS]; |
---|
| 82 | struct utmp ut; |
---|
| 83 | register FILE *uf; |
---|
| 84 | |
---|
| 85 | #ifdef LOCALE |
---|
| 86 | setlocale(LC_ALL, ""); |
---|
| 87 | #endif |
---|
| 88 | invo_name = r1bindex (argv[0], '/'); |
---|
| 89 | |
---|
| 90 | /* read user profile/context */ |
---|
| 91 | context_read(); |
---|
| 92 | |
---|
| 93 | mts_init (invo_name); |
---|
| 94 | arguments = getarguments (invo_name, argc, argv, 1); |
---|
| 95 | argp = arguments; |
---|
| 96 | |
---|
| 97 | while ((cp = *argp++)) { |
---|
| 98 | if (*cp == '-') { |
---|
| 99 | switch (smatch (++cp, switches)) { |
---|
| 100 | case AMBIGSW: |
---|
| 101 | ambigsw (cp, switches); |
---|
| 102 | done (1); |
---|
| 103 | case UNKWNSW: |
---|
| 104 | vec[vecp++] = --cp; |
---|
| 105 | continue; |
---|
| 106 | |
---|
| 107 | case HELPSW: |
---|
| 108 | snprintf (buf, sizeof(buf), "%s [command ...]", invo_name); |
---|
| 109 | print_help (buf, switches, 1); |
---|
| 110 | done (1); |
---|
| 111 | case VERSIONSW: |
---|
| 112 | print_version(invo_name); |
---|
| 113 | done (1); |
---|
| 114 | |
---|
| 115 | case BIFFSW: |
---|
| 116 | biff = 1; |
---|
| 117 | continue; |
---|
| 118 | |
---|
| 119 | case FORMSW: |
---|
| 120 | if (!(form = *argp++) || *form == '-') |
---|
| 121 | adios (NULL, "missing argument to %s", argp[-2]); |
---|
| 122 | format = NULL; |
---|
| 123 | continue; |
---|
| 124 | case FMTSW: |
---|
| 125 | if (!(format = *argp++) || *format == '-') |
---|
| 126 | adios (NULL, "missing argument to %s", argp[-2]); |
---|
| 127 | form = NULL; |
---|
| 128 | continue; |
---|
| 129 | |
---|
| 130 | case WIDTHSW: |
---|
| 131 | if (!(cp = *argp++) || *cp == '-') |
---|
| 132 | adios(NULL, "missing argument to %s", argp[-2]); |
---|
| 133 | width = atoi(cp); |
---|
| 134 | continue; |
---|
| 135 | case NLSW: |
---|
| 136 | newline = 1; |
---|
| 137 | continue; |
---|
| 138 | case NNLSW: |
---|
| 139 | newline = 0; |
---|
| 140 | continue; |
---|
| 141 | case BELSW: |
---|
| 142 | bell = 1; |
---|
| 143 | continue; |
---|
| 144 | case NBELSW: |
---|
| 145 | bell = 0; |
---|
| 146 | continue; |
---|
| 147 | |
---|
| 148 | } |
---|
| 149 | } |
---|
| 150 | vec[vecp++] = cp; |
---|
| 151 | } |
---|
| 152 | vec[vecp] = 0; |
---|
| 153 | |
---|
| 154 | if ((md = vecp ? message_fd (vec) : header_fd ()) == NOTOK) |
---|
| 155 | exit (RCV_MBX); |
---|
| 156 | |
---|
| 157 | user = getusername(); |
---|
| 158 | if ((uf = fopen (UTMP_FILE, "r")) == NULL) |
---|
| 159 | exit (RCV_MBX); |
---|
| 160 | |
---|
| 161 | while (fread ((char *) &ut, sizeof(ut), 1, uf) == 1) |
---|
| 162 | if (ut.ut_name[0] != 0 |
---|
| 163 | && strncmp (user, ut.ut_name, sizeof(ut.ut_name)) == 0) { |
---|
| 164 | strncpy (tty, ut.ut_line, sizeof(ut.ut_line)); |
---|
| 165 | alert (tty, md); |
---|
| 166 | } |
---|
| 167 | |
---|
| 168 | fclose (uf); |
---|
| 169 | exit (RCV_MOK); |
---|
| 170 | } |
---|
| 171 | |
---|
| 172 | |
---|
| 173 | static RETSIGTYPE |
---|
| 174 | alrmser (int i) |
---|
| 175 | { |
---|
| 176 | #ifndef RELIABLE_SIGNALS |
---|
| 177 | SIGNAL (SIGALRM, alrmser); |
---|
| 178 | #endif |
---|
| 179 | |
---|
| 180 | longjmp (myctx, 1); |
---|
| 181 | } |
---|
| 182 | |
---|
| 183 | |
---|
| 184 | static int |
---|
| 185 | message_fd (char **vec) |
---|
| 186 | { |
---|
| 187 | pid_t child_id; |
---|
| 188 | int bytes, fd, seconds; |
---|
| 189 | char tmpfil[BUFSIZ]; |
---|
| 190 | struct stat st; |
---|
| 191 | |
---|
| 192 | unlink (mktemp (strncpy (tmpfil, "/tmp/rcvttyXXXXX", sizeof(tmpfil)))); |
---|
| 193 | if ((fd = open (tmpfil, O_RDWR | O_CREAT | O_TRUNC, 0600)) == NOTOK) |
---|
| 194 | return header_fd (); |
---|
| 195 | unlink (tmpfil); |
---|
| 196 | |
---|
| 197 | if ((child_id = vfork()) == NOTOK) { |
---|
| 198 | /* fork error */ |
---|
| 199 | close (fd); |
---|
| 200 | return header_fd (); |
---|
| 201 | } else if (child_id) { |
---|
| 202 | /* parent process */ |
---|
| 203 | if (!setjmp (myctx)) { |
---|
| 204 | SIGNAL (SIGALRM, alrmser); |
---|
| 205 | bytes = fstat(fileno (stdin), &st) != NOTOK ? (int) st.st_size : 100; |
---|
| 206 | |
---|
| 207 | /* amount of time to wait depends on message size */ |
---|
| 208 | if (bytes <= 100) { |
---|
| 209 | /* give at least 5 minutes */ |
---|
| 210 | seconds = 300; |
---|
| 211 | } else if (bytes >= 90000) { |
---|
| 212 | /* but 30 minutes should be long enough */ |
---|
| 213 | seconds = 1800; |
---|
| 214 | } else { |
---|
| 215 | seconds = (bytes / 60) + 300; |
---|
| 216 | } |
---|
| 217 | alarm ((unsigned int) seconds); |
---|
| 218 | pidwait(child_id, OK); |
---|
| 219 | alarm (0); |
---|
| 220 | |
---|
| 221 | if (fstat (fd, &st) != NOTOK && st.st_size > (off_t) 0) |
---|
| 222 | return fd; |
---|
| 223 | } else { |
---|
| 224 | /* |
---|
| 225 | * Ruthlessly kill the child and anything |
---|
| 226 | * else in its process group. |
---|
| 227 | */ |
---|
| 228 | KILLPG(child_id, SIGKILL); |
---|
| 229 | } |
---|
| 230 | close (fd); |
---|
| 231 | return header_fd (); |
---|
| 232 | } |
---|
| 233 | |
---|
| 234 | /* child process */ |
---|
| 235 | rewind (stdin); |
---|
| 236 | if (dup2 (fd, 1) == NOTOK || dup2 (fd, 2) == NOTOK) |
---|
| 237 | _exit (-1); |
---|
| 238 | closefds (3); |
---|
| 239 | setpgid ((pid_t) 0, getpid ()); /* put in own process group */ |
---|
| 240 | execvp (vec[0], vec); |
---|
| 241 | _exit (-1); |
---|
| 242 | } |
---|
| 243 | |
---|
| 244 | |
---|
| 245 | static int |
---|
| 246 | header_fd (void) |
---|
| 247 | { |
---|
| 248 | int fd; |
---|
| 249 | char *nfs, tmpfil[BUFSIZ]; |
---|
| 250 | |
---|
| 251 | strncpy (tmpfil, m_tmpfil (invo_name), sizeof(tmpfil)); |
---|
| 252 | if ((fd = open (tmpfil, O_RDWR | O_CREAT | O_TRUNC, 0600)) == NOTOK) |
---|
| 253 | return NOTOK; |
---|
| 254 | unlink (tmpfil); |
---|
| 255 | |
---|
| 256 | rewind (stdin); |
---|
| 257 | |
---|
| 258 | /* get new format string */ |
---|
| 259 | nfs = new_fs (form, format, SCANFMT); |
---|
| 260 | scan (stdin, 0, 0, nfs, width, 0, 0, NULL, 0L, 0); |
---|
| 261 | if (newline) |
---|
| 262 | write (fd, "\n\r", 2); |
---|
| 263 | write (fd, scanl, strlen (scanl)); |
---|
| 264 | if (bell) |
---|
| 265 | write (fd, "\007", 1); |
---|
| 266 | |
---|
| 267 | return fd; |
---|
| 268 | } |
---|
| 269 | |
---|
| 270 | |
---|
| 271 | static void |
---|
| 272 | alert (char *tty, int md) |
---|
| 273 | { |
---|
| 274 | int i, td, mask; |
---|
| 275 | char buffer[BUFSIZ], ttyspec[BUFSIZ]; |
---|
| 276 | struct stat st; |
---|
| 277 | |
---|
| 278 | snprintf (ttyspec, sizeof(ttyspec), "/dev/%s", tty); |
---|
| 279 | |
---|
| 280 | /* |
---|
| 281 | * The mask depends on whether we are checking for |
---|
| 282 | * write permission based on `biff' or `mesg'. |
---|
| 283 | */ |
---|
| 284 | mask = biff ? S_IEXEC : (S_IWRITE >> 3); |
---|
| 285 | if (stat (ttyspec, &st) == NOTOK || (st.st_mode & mask) == 0) |
---|
| 286 | return; |
---|
| 287 | |
---|
| 288 | if (!setjmp (myctx)) { |
---|
| 289 | SIGNAL (SIGALRM, alrmser); |
---|
| 290 | alarm (2); |
---|
| 291 | td = open (ttyspec, O_WRONLY); |
---|
| 292 | alarm (0); |
---|
| 293 | if (td == NOTOK) |
---|
| 294 | return; |
---|
| 295 | } else { |
---|
| 296 | alarm (0); |
---|
| 297 | return; |
---|
| 298 | } |
---|
| 299 | |
---|
| 300 | lseek (md, (off_t) 0, SEEK_SET); |
---|
| 301 | |
---|
| 302 | while ((i = read (md, buffer, sizeof(buffer))) > 0) |
---|
| 303 | if (write (td, buffer, i) != i) |
---|
| 304 | break; |
---|
| 305 | |
---|
| 306 | close (td); |
---|
| 307 | } |
---|
| 308 | |
---|