Initial commit of an unmodified 2.11BSD source tree taken from a boot tape.
[211bsd.git] / libexec / comsat / comsat.c
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of California at Berkeley. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific written prior permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12
13 #if     !defined(lint) && defined(DOSCCS)
14 char copyright[] =
15 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
16  All rights reserved.\n";
17
18 static char sccsid[] = "@(#)comsat.c    5.11.2 (2.11BSD) 1999/9/15";
19 #endif
20
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <sys/param.h>
24 #include <sys/socket.h>
25 #include <sys/stat.h>
26 #include <sys/file.h>
27 #include <sys/wait.h>
28
29 #include <netinet/in.h>
30
31 #include <stdio.h>
32 #include <sgtty.h>
33 #include <utmp.h>
34 #include <signal.h>
35 #include <errno.h>
36 #include <netdb.h>
37 #include <syslog.h>
38 #include <strings.h>
39 #include <time.h>
40
41 /*
42  * comsat
43  */
44 int     debug = 0;
45 #define dsyslog if (debug) syslog
46
47 #define MAXIDLE 120
48
49 char    hostname[MAXHOSTNAMELEN];
50 struct  utmp *utmp = NULL;
51 time_t  lastmsgtime;
52 int     nutmp, uf;
53
54 main(argc, argv)
55         int argc;
56         char **argv;
57 {
58         register int cc;
59         char msgbuf[100];
60         struct sockaddr_in from;
61         int fromlen, reapchildren(), onalrm();
62         sigset_t set, oset;
63
64         /* verify proper invocation */
65         fromlen = sizeof (from);
66         if (getsockname(0, &from, &fromlen) < 0) {
67                 fprintf(stderr, "%s: ", argv[0]);
68                 perror("getsockname");
69                 exit(1);
70         }
71         openlog("comsat", LOG_PID, LOG_DAEMON);
72         if (chdir("/usr/spool/mail")) {
73                 syslog(LOG_ERR, "chdir: /usr/spool/mail: %m");
74                 exit(1);
75         }
76         if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) {
77                 syslog(LOG_ERR, ".main: %s: %m", _PATH_UTMP);
78                 (void) recv(0, msgbuf, sizeof (msgbuf) - 1, 0);
79                 exit(1);
80         }
81         (void)time(&lastmsgtime);
82         (void)gethostname(hostname, sizeof (hostname));
83         onalrm();
84         (void)signal(SIGALRM, onalrm);
85         (void)signal(SIGTTOU, SIG_IGN);
86         (void)signal(SIGCHLD, reapchildren);
87         for (;;) {
88                 cc = recv(0, msgbuf, sizeof (msgbuf) - 1, 0);
89                 if (cc <= 0) {
90                         sleep(1);
91                         continue;
92                 }
93                 if (!nutmp)             /* no one has logged in yet */
94                         continue;
95                 sigemptyset(&set);
96                 sigaddset(&set, SIGALRM);
97                 sigprocmask(SIG_BLOCK, &set, &oset);
98                 msgbuf[cc] = 0;
99                 (void)time(&lastmsgtime);
100                 mailfor(msgbuf);
101                 sigprocmask(SIG_SETMASK, &oset, NULL);
102         }
103 }
104
105 reapchildren()
106 {
107         while (wait4(-1, NULL, WNOHANG, NULL) > 0)
108                 ;
109 }
110
111 onalrm()
112 {
113         static u_int utmpsize;          /* last malloced size for utmp */
114         static u_int utmpmtime;         /* last modification time for utmp */
115         struct stat statbf;
116
117         if (time((time_t *)NULL) - lastmsgtime >= MAXIDLE)
118                 exit(0);
119         (void)alarm((u_int)15);
120         (void)fstat(uf, &statbf);
121         if (statbf.st_mtime > utmpmtime) {
122                 utmpmtime = statbf.st_mtime;
123                 if (statbf.st_size > utmpsize) {
124                         utmpsize = statbf.st_size + 10 * sizeof(struct utmp);
125                         if (utmp)
126                                 utmp = (struct utmp *)realloc((char *)utmp, utmpsize);
127                         else
128                                 utmp = (struct utmp *)malloc(utmpsize);
129                         if (!utmp) {
130                                 syslog(LOG_ERR, "malloc failed");
131                                 exit(1);
132                         }
133                 }
134                 (void)lseek(uf, 0L, L_SET);
135                 nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp);
136         }
137 }
138
139 mailfor(name)
140         char *name;
141 {
142         register struct utmp *utp = &utmp[nutmp];
143         register char *cp;
144         off_t offset;
145
146         if (!(cp = index(name, '@')))
147                 return;
148         *cp = '\0';
149         offset = atol(cp + 1);
150         while (--utp >= utmp)
151                 if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name)))
152                         notify(utp, offset);
153 }
154
155 static char     *cr;
156
157 notify(utp, offset)
158         register struct utmp *utp;
159         off_t offset;
160 {
161         static char tty[20] = "/dev/";
162         struct sgttyb gttybuf;
163         FILE *tp;
164         char name[sizeof (utmp[0].ut_name) + 1];
165         struct stat stb;
166
167         (void)strncpy(tty + 5, utp->ut_line, sizeof(utp->ut_line));
168         if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) {
169                 dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty);
170                 return;
171         }
172         dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty);
173         if (fork())
174                 return;
175         (void)signal(SIGALRM, SIG_DFL);
176         (void)alarm((u_int)30);
177         if ((tp = fopen(tty, "w")) == NULL) {
178                 dsyslog(LOG_ERR, "fopen of tty %s failed", tty);
179                 _exit(-1);
180         }
181         (void)ioctl(fileno(tp), TIOCGETP, &gttybuf);
182         cr = (gttybuf.sg_flags&CRMOD) && !(gttybuf.sg_flags&RAW) ? "" : "\r";
183         (void)strncpy(name, utp->ut_name, sizeof (utp->ut_name));
184         name[sizeof (name) - 1] = '\0';
185         fprintf(tp, "%s\n\007New mail for %s@%.*s\007 has arrived:%s\n----%s\n",
186             cr, name, sizeof (hostname), hostname, cr, cr);
187         jkfprintf(tp, name, offset);
188         fclose(tp);
189         _exit(0);
190 }
191
192 jkfprintf(tp, name, offset)
193         register FILE *tp;
194         char name[];
195         off_t offset;
196 {
197         register char *cp;
198         register FILE *fi;
199         int linecnt, charcnt, inheader;
200         char line[BUFSIZ];
201
202         if ((fi = fopen(name, "r")) == NULL)
203                 return;
204         (void)fseek(fi, offset, L_SET);
205         /* 
206          * Print the first 7 lines or 560 characters of the new mail
207          * (whichever comes first).  Skip header crap other than
208          * From, Subject, To, and Date.
209          */
210         linecnt = 7;
211         charcnt = 560;
212         inheader = 1;
213         while (fgets(line, sizeof (line), fi) != NULL) {
214                 if (inheader) {
215                         if (line[0] == '\n') {
216                                 inheader = 0;
217                                 continue;
218                         }
219                         if (line[0] == ' ' || line[0] == '\t' ||
220                             strncmp(line, "From:", 5) &&
221                             strncmp(line, "Subject:", 8))
222                                 continue;
223                 }
224                 if (cp = index(line, '\n'))
225                         *cp = '\0';
226                 fprintf(tp, "%s%s\n", line, cr);
227                 charcnt -= strlen(line);
228                 if (--linecnt <= 0 || charcnt <= 0) {
229                         fprintf(tp, "...more...%s\n", cr);
230                         return;
231                 }
232         }
233         fprintf(tp, "----%s\n", cr);
234 }