|
|
1.1 root 1: /*
2: * msgs - system wide messages program
3: */
4:
5: #include <stdio.h>
6: #include <sys/stat.h>
7: #include <sys/dir.h>
8: #include <ctype.h>
9: #include <signal.h>
10:
11: #define BSIZE 512
12: #define NLINE 512
13: #define PAGELEN 20
14:
15: char mline[NLINE]; /* line of mail file */
16:
17: int qflag; /* query new messages */
18: int msgsnum; /* command line numeric argument */
19: int exstat; /* exit status */
20:
21: FILE *boundfp; /* file pointer for boundname */
22: char *boundformat = "LOWMSG=%d\tHIGHMSG=%d\n";
23: unsigned int lowmsg; /* lowest number message in msgsdir */
24: unsigned int highmsg; /* highest number message in msgsdir */
25:
26: FILE *mailfp; /* file pointer to mailfile */
27: char *mailfile = "/usr/spool/mail/msgs";
28: char *msgsdir = "/usr/msgs";
29: char *rcname = ".msgsrc";
30: char *rcformat = "MSGSNUM=%d\n";
31: char *boundname = "/usr/msgs/bounds";
32: char *home;
33: char *scatname;
34:
35: #define FATAL 1 /* used by badmsg() */
36: #define NONFATAL 0
37:
38: extern char *getenv();
39:
40: main(argc, argv)
41: int argc;
42: char *argv[];
43: {
44: int rcnum, num;
45:
46: if ( argc > 1 )
47: doargs(argc, argv);
48: dobounds();
49: readmail();
50: rcnum = readrc();
51: num = (msgsnum<=0) ? rcnum+msgsnum : msgsnum;
52: if ( (num=domsgs(num)) > rcnum )
53: writerc(num);
54: exit(exstat);
55: }
56:
57: /*
58: * Fix the boundname file and set the global variables
59: * lowmsg and highmsg to the appropriate values.
60: */
61:
62: dobounds()
63: {
64: struct stat st;
65:
66: if ( stat(boundname, &st) < 0 ) {
67: calcbounds();
68: return;
69: }
70:
71: if ( (boundfp=fopen(boundname,"rw")) == NULL )
72: badmsg(FATAL, "Can't open read/write: %s", boundname);
73:
74: if ( fscanf(boundfp, boundformat, &lowmsg, &highmsg) != 2 )
75: calcbounds();
76: }
77:
78: /*
79: * Recreate the boundname file
80: */
81:
82: calcbounds()
83: {
84: int dirfd;
85: char buf[BSIZE];
86: int num, size;
87: struct direct *dentry;
88:
89: if ( (boundfp=fopen(boundname,"w")) == NULL )
90: badmsg(FATAL, "Can't open: %s", boundname);
91:
92: if ( chmod(boundname, 0666) < 0 )
93: badmsg(FATAL, "Can't chmod: %s", boundname);
94:
95: if ( (dirfd=open(msgsdir, 0)) < 0 )
96: badmsg(FATAL, "Can't open: %s", msgsdir);
97:
98: highmsg = 0;
99: lowmsg = ~000;
100:
101: while ( (size=read(dirfd, buf, BSIZE)) != 0 ) {
102: dentry = (struct direct *) buf;
103: while ( (size-=sizeof(struct direct)) >= 0 ) {
104:
105: if ( dentry->d_ino &&
106: (num=decode(dentry->d_name)) > 0 ) {
107: if ( num > highmsg )
108: highmsg = num;
109: if ( num < lowmsg )
110: lowmsg = num;
111: }
112: dentry++;
113: }
114: }
115:
116: if ( highmsg==0 )
117: lowmsg = 0;
118:
119: fprintf(boundfp, boundformat, lowmsg, highmsg);
120: }
121:
122: /*
123: * Does an atoi of the given string once it is certain that
124: * it is all digits.
125: */
126:
127: decode(str)
128: char *str;
129: {
130: register int i;
131:
132: for (i=0; i<DIRSIZ; i++) {
133: if ( str[i] == '\0' )
134: break;
135: if ( i==0 && str[0] == '-' )
136: continue;
137: if ( !isascii(str[i]) || !isdigit(str[i]) )
138: return(0);
139: }
140:
141: return(atoi(str));
142: }
143:
144: /*
145: * Process the mail in mailfile, and put it in the msgsdir.
146: */
147:
148: readmail()
149: {
150: struct stat st;
151: int fd;
152:
153: if ( stat(mailfile, &st) < 0 ) {
154: badmsg(NONFATAL,"Can't stat: %s", mailfile);
155: return;
156: }
157:
158: if ( st.st_size == 0 ) {
159: fclose(boundfp);
160: return;
161: }
162:
163: if ( (mailfp=fopen(mailfile, "rw")) == NULL ) {
164: badmsg(NONFATAL,"Can't open read/write: %s", mailfile);
165: return;
166: }
167:
168: if ( chdir(msgsdir) < 0 )
169: badmsg(FATAL, "Can't chdir: %s", msgsdir);
170:
171: while ( dumpmsg() ) ;
172:
173: fclose(mailfp);
174: if ( (fd=creat(mailfile, 0644)) < 0 )
175: badmsg(FATAL, "Can't creat: %s", mailfile);
176: close(fd);
177:
178: rewind(boundfp);
179: fprintf(boundfp, boundformat, lowmsg, highmsg);
180: fclose(boundfp);
181: }
182:
183: /*
184: * Dump the current message from the mailfile into the msgsdir
185: */
186:
187: dumpmsg()
188: {
189: char *tmp;
190: char numname[10];
191: FILE *fp;
192:
193: while ( (tmp=fgets(mline, NLINE, mailfp)) != NULL )
194: if ( strcmp(mline, "\1\1\n") )
195: break;
196:
197: if ( tmp == NULL )
198: return(0);
199:
200: sprintf(numname, "%d", ++highmsg);
201:
202: if ( (fp=fopen(numname,"w")) == NULL )
203: badmsg(FATAL, "Can't open to write: %s/%s", msgsdir, numname);
204:
205: do {
206: fputs(mline, fp);
207: if ( strcmp(mline, "\1\1\n") == 0 )
208: break;
209: } while ( fgets(mline, NLINE, mailfp) != NULL );
210:
211: fclose(fp);
212: if ( lowmsg == 0 )
213: lowmsg = 1;
214: return(1);
215: }
216:
217: /*
218: * Display the messages in msgsdir beginning with
219: * message number (num)
220: */
221:
222: domsgs(num)
223: int num;
224: {
225: int intexit();
226:
227: signal(SIGINT, intexit);
228: signal(SIGPIPE, intexit);
229:
230: if ( chdir(msgsdir) < 0 )
231: badmsg(FATAL, "Can't chdir: %s", msgsdir);
232:
233: if ( num < 1 || num < lowmsg )
234: num = lowmsg;
235:
236: if ( qflag ) {
237: if (num <= highmsg)
238: printf("There are new messages.\n");
239: else
240: printf("No new messages.\n");
241: return(num);
242: }
243:
244: if ( ((scatname=getenv("PAGER")) != NULL) &&
245: (strlen(scatname) == 0) )
246: scatname = NULL;
247:
248: while ( num <= highmsg ) {
249: if (do_one(num) < 0)
250: break;
251: num += 1;
252: }
253:
254: return(num);
255: }
256:
257: /*
258: * Display a single message, return (-1) if user
259: * requests to quit.
260: */
261:
262: do_one(num)
263: int num;
264: {
265: FILE *fp;
266: char numname[10];
267: char ch, inputchar();
268: long offset = 0;
269: int newnum;
270: struct stat st;
271:
272: sprintf(numname, "%d", num);
273:
274: if ( stat(numname, &st) < 0 )
275: return(0);
276:
277: if ( (fp=fopen(numname, "r")) == NULL )
278: return(0);
279:
280: printf("\nMessage Number %d [%ld chars]\n", num, st.st_size);
281:
282: while ( fgets(mline, NLINE, fp) != NULL ) {
283: if ( (strncmp(mline, "Date: ", 6) == 0) ||
284: (strncmp(mline, "From: ", 6) == 0) ||
285: (strncmp(mline, "To: ", 4 ) == 0) ||
286: (strncmp(mline, "cc: ", 4 ) == 0) ||
287: havesubject() ) {
288: printf("%s", mline);
289: offset = ftell(fp);
290: continue;
291: }
292: if (offset)
293: break;
294: }
295:
296: if ( !offset ) {
297: fclose(fp);
298: return(0);
299: }
300: fseek(fp, offset, 0);
301:
302: switch( ch=inputchar() ) {
303: case 'Y':
304: dumpit(fp);
305: case 'N':
306: fclose(fp);
307: return(0);
308: case 'Q':
309: fclose(fp);
310: return(-1);
311: default:
312: ungetc(ch, stdin);
313: scanf("%d", &newnum);
314: while ( getchar() != '\n' ) ;
315: break;
316: case '-':
317: newnum = num - 1;
318: break;
319: }
320: fclose(fp);
321: if ( do_one(newnum) < 0 )
322: return(-1);
323: return(do_one(num));
324: }
325:
326: /*
327: * Determine if we have a subject in mline.
328: */
329:
330: havesubject()
331: {
332: static char *subject="subject:";
333: register char *x = subject;
334: register char *y = mline;
335:
336: while ( *x )
337: if ( tolower(*y++)!=*x++ )
338: return(0);
339:
340: return(1);
341: }
342:
343: /*
344: * Print out the text of the message in a scat like
345: * manner.
346: */
347:
348: dumpit(fp)
349: FILE *fp;
350: {
351: FILE *xfp;
352: char ch, *cmdname;
353:
354: if ( scatname != NULL ) {
355: sprintf(cmdname=&mline[0], "%s", scatname);
356: if ( (xfp=popen(cmdname, "w")) == NULL )
357: badmsg(FATAL, "Can't open pipe for writing: %s",
358: cmdname);
359: while ( (ch=getc(fp)) != EOF )
360: if ( putc(ch, xfp) == EOF )
361: intexit(SIGPIPE);
362: if ( ((pclose(xfp)>>8)&0xFF) == SIGINT )
363: intexit(SIGINT);
364: } else {
365: while ( (ch=getc(fp)) != EOF )
366: putc(ch, stdout);
367: }
368: }
369:
370: intexit(status)
371: {
372: putc('\n', stdout);
373: _exit(status);
374: }
375:
376: char
377: inputchar()
378: {
379: char ch;
380:
381: for (;;) {
382: printf("[ynq]: ");
383: while ( (ch=getchar()) == ' ' || ch == '\t' ) ;
384: if ( isalpha(ch) )
385: ch = toupper(ch);
386:
387: if ( ch == '\n' )
388: return('Y');
389:
390: if ( isdigit(ch) )
391: return(ch);
392:
393: while (getchar() != '\n') ;
394:
395: if ( ch == 'N' || ch == 'Y' || ch == 'Q' || ch == '-')
396: return(ch);
397: }
398: }
399:
400: /*
401: * Returns the next message number to read according the the
402: * file (.msgsrc) in the HOME directory. Returns message
403: * number (1) if any problems.
404: */
405:
406: readrc()
407: {
408: FILE *msgsrc;
409: struct stat st;
410: int num;
411:
412: if ( (home=getenv("HOME")) == NULL ) {
413: badmsg(NONFATAL,"No HOME variable in environment.");
414: return(1);
415: }
416:
417: if ( chdir(home) < 0 ) {
418: badmsg(NONFATAL,"Can't chdir to %s", home);
419: return(1);
420: }
421:
422: if ( stat(rcname, &st) < 0 )
423: return(1);
424:
425: if ( (msgsrc=fopen(rcname,"r")) == NULL ) {
426: badmsg(NONFATAL, "Can't open to read: %s/%s", home, rcname);
427: return(1);
428: }
429:
430: if ( fscanf(msgsrc, rcformat, &num) != 1 ) {
431: badmsg(NONFATAL, "Badly formatted file: %s/%s", home, rcname);
432: return(1);
433: }
434:
435: fclose(msgsrc);
436: return(num);
437: }
438:
439: /*
440: * Update the rcname file in the user's home directory.
441: */
442:
443: writerc(num)
444: int num;
445: {
446: FILE *msgsrc;
447:
448: if ( chdir(home) < 0 )
449: badmsg(FATAL,"Can't chdir to %s", home);
450:
451: if (setuid(getuid())< 0)
452: badmsg(FATAL, "Can't setuid to %d\n", getuid());
453:
454: if ( (msgsrc=fopen(rcname,"w")) == NULL )
455: badmsg(FATAL, "Can't open to write: %s/%s", home, rcname);
456:
457: fprintf(msgsrc, rcformat, num);
458: fclose(msgsrc);
459: }
460:
461: /*
462: * Process command line arguments.
463: */
464:
465: doargs(argc, argv)
466: register int argc;
467: register char *argv[];
468: {
469: if ( argc > 2 )
470: usage();
471:
472: if ( strcmp(argv[1], "-q") == 0 )
473: qflag = 1;
474: else if ( (msgsnum=decode(argv[1])) == 0 )
475: usage();
476: }
477:
478: /*
479: * Issue error message. flag is either NONFATAL or FATAL
480: */
481:
482: badmsg(flag, x)
483: int flag;
484: char *x;
485: {
486: fprintf(stderr, "msgs: %r\n", &x);
487: if ( flag == FATAL)
488: exit(1);
489: else
490: exstat = 1;
491: }
492:
493: char *usemsg = "\n\
494: Usage: msgs [ -q ] [ number ]\n\
495: -q : query existence of new messages\n\
496: number: greater than zero, start with that message number\n\
497: less than zero, start backward that many from current\n\n";
498:
499: usage()
500: {
501: fprintf(stderr, usemsg);
502: exit(1);
503: }
504:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.