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