#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <setjmp.h>
#include <signal.h>
#include <dirent.h>
#include <pwd.h>
#include <time.h>
#include <locale.h>
#define INDENT 3
#define RD_WR_ALL (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
#define DATE_FMT "%a %b %e %H:%M:%S %Y"
char *ignore[] = {
"core",
NULL
};
struct n_file {
long n_time;
char n_name[MAXNAMLEN];
} *n_list;
char NEWS[] = "/var/news";
int aopt = 0;
int n_count;
int number_read;
int nopt = 0;
int optsw;
int opt = 0;
int sopt = 0;
char stdbuf[BUFSIZ];
char time_buf[50];
jmp_buf save_addr;
void all_news(void);
int ck_num(void);
void count(char *);
void initialize(void);
void late_news(void(*)(), int);
void notify(char *);
void print_item(char *);
void read_dir(void);
int
main(int argc, char **argv)
{
int i;
(void)setlocale(LC_ALL, "");
setbuf (stdout, stdbuf);
initialize();
read_dir();
if (argc <= 1) {
late_news (print_item, 1);
ck_num();
}
else while ((optsw = getopt(argc, argv, "ans")) != EOF)
switch(optsw) {
case 'a':
aopt++;
opt++;
break;
case 'n':
nopt++;
opt++;
break;
case 's':
sopt++;
opt++;
break;
default:
fprintf (stderr, "usage: news [-a] [-n] [-s] [items]\n");
exit (1);
}
if (opt > 1) {
fprintf(stderr, "news: options are mutually exclusive\n");
exit(1);
}
if (opt > 0 && argc > 2) {
fprintf(stderr, "news: options are not allowed with file names\n");
exit(1);
}
if (aopt) {
all_news();
ck_num();
exit(0);
}
if (nopt) {
late_news (notify, 0);
ck_num();
exit(0);
}
if (sopt) {
late_news (count, 0);
exit(0);
}
for (i=1; i<argc; i++) print_item (argv[i]);
return (0);
}
void
read_dir(void)
{
struct dirent *nf, *readdir();
struct stat sbuf;
char fname[MAXNAMLEN];
DIR *dirp;
int i, j;
if ((dirp = opendir(".")) == NULL) {
fprintf (stderr, "Cannot open %s\n", NEWS);
exit (1);
}
n_count = 0;
while (nf = readdir(dirp)) {
strncpy (fname, nf->d_name, (unsigned) strlen(nf->d_name) + 1);
if (nf->d_ino != (ino_t)0 && stat (fname, &sbuf) >= 0
&& (sbuf.st_mode & S_IFMT) == S_IFREG) {
register char **p;
p = ignore;
while (*p && strncmp (*p, nf->d_name, MAXNAMLEN))
++p;
if (!*p) {
if (n_count++ > 0)
n_list = (struct n_file *)
realloc ((char *) n_list,
(unsigned)
(sizeof (struct n_file)
* n_count));
else
n_list = (struct n_file *) malloc
((unsigned)
(sizeof (struct n_file) *
n_count));
if (n_list == NULL) {
fprintf (stderr, "No storage\n");
exit (1);
}
n_list[n_count-1].n_time = sbuf.st_mtime;
strncpy (n_list[n_count-1].n_name,
nf->d_name, MAXNAMLEN);
}
}
}
for (i=1; i<n_count; i++)
for (j=0; j<i; j++)
if (n_list[j].n_time < n_list[i].n_time) {
struct n_file temp;
temp = n_list[i];
n_list[i] = n_list[j];
n_list[j] = temp;
}
closedir(dirp);
}
void
initialize(void)
{
if (signal (SIGQUIT, SIG_IGN) != (void(*)())SIG_IGN)
signal (SIGQUIT, _exit);
umask (((~(S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) & S_IAMB));
if (chdir (NEWS) < 0) {
fprintf (stderr, "Cannot chdir to %s\n", NEWS);
exit (1);
}
}
void
all_news(void)
{
int i;
for (i=0; i<n_count; i++)
print_item (n_list[i].n_name);
}
void
print_item(char *f)
{
FILE *fd;
char fname[MAXNAMLEN+1];
static int firstitem = 1;
void onintr();
struct passwd *getpwuid();
if (f == NULL) {
return;
}
strncpy (fname, f, MAXNAMLEN);
fname[MAXNAMLEN] = '\0';
if ((fd = fopen (fname, "r")) == NULL)
printf ("Cannot open %s/%s\n", NEWS, fname);
else {
register int c, ip, op;
struct stat sbuf;
struct passwd *pw;
fstat (fileno (fd), &sbuf);
if (firstitem) {
firstitem = 0;
putchar ('\n');
}
if (setjmp(save_addr))
goto finish;
if (signal(SIGINT, SIG_IGN) != (void(*)())SIG_IGN)
signal(SIGINT, onintr);
printf ("%s ", fname);
pw = getpwuid (sbuf.st_uid);
if (pw)
printf ("(%s)", pw->pw_name);
else
printf (".....");
cftime(time_buf, DATE_FMT, &sbuf.st_mtime);
printf (" %s\n", time_buf);
op = 0;
ip = INDENT;
while ((c = getc (fd)) != EOF) {
switch (c) {
case '\r':
case '\n':
putchar (c);
op = 0;
ip = INDENT;
break;
case ' ':
ip++;
break;
case '\b':
if (ip > INDENT)
ip--;
break;
case '\t':
ip = ((ip - INDENT + 8) & -8) + INDENT;
break;
default:
while (ip < op) {
putchar ('\b');
op--;
}
while ((ip & -8) > (op & -8)) {
putchar ('\t');
op = (op + 8) & -8;
}
while (ip > op) {
putchar (' ');
op++;
}
putchar (c);
ip++;
op++;
break;
}
}
fflush (stdout);
finish:
putchar ('\n');
fclose (fd);
number_read++;
if (signal(SIGINT, SIG_IGN) != (void(*)())SIG_IGN)
signal(SIGINT, SIG_DFL);
}
}
void
late_news(void(*emit)(), int update)
{
long cutoff;
int i;
char fname[50], *cp;
struct stat newstime;
int fd;
struct {
long actime, modtime;
} utb;
extern char *getenv();
cp = getenv ("HOME");
if (cp == NULL) {
fprintf (stderr, "Cannot find HOME variable\n");
exit (1);
}
strcpy (fname, cp);
strcat (fname, "/");
strcat (fname, ".news_time");
cutoff = stat (fname, &newstime) < 0? 0: newstime.st_mtime;
for (i=0; i<n_count && n_list[i].n_time > cutoff; i++) {
(*emit) (n_list[i].n_name);
number_read++;
}
(*emit) ((char *) NULL);
fflush (stdout);
if (update) {
if (n_count > 0 && (fd = creat (fname, RD_WR_ALL)) >= 0) {
utb.actime = utb.modtime = n_list[0].n_time;
close (fd);
utime (fname, &utb);
}
}
}
void
notify(char *s)
{
static int first = 1;
if (s) {
if (first) {
first = 0;
printf ("news:", NEWS);
}
printf (" %.14s", s);
} else if (!first)
putchar ('\n');
}
void
count(char *s)
{
static int nitems = 0;
if (s)
nitems++;
else {
if (nitems) {
printf ("%d news item", nitems);
if (nitems != 1)
putchar ('s');
printf (".\n");
}
else printf("No news.\n");
}
}
void
onintr()
{
sleep(2);
longjmp(save_addr, 1);
}
int
ck_num(void)
{
if (sopt && !number_read) printf("No news.\n");
return(0);
}