/*
 * W-NEWS       A simple NEWS processing package.
 *              This little program checks to see if the user has any
 *              news articles pending.  It can be used standalone, or
 *              it can be called from the /etc/profile startup file.
 *
 * Usage:       checknews [-nqvy] [ -N ng_list ]
 *
 * Version:     @(#)checknews.c	4.50	03-Feb-1995
 *
 * Authors:     Fred N. van Kempen, <waltje@Infomagic.COM>
 *		Miquel van Smoorenburg, <miquels@drinkel.ow.org>
 *		Copyright 1988-1993 MicroWalt Corporation
 *		Copyright 1994,1995 Cistron Software C.V.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 */
#include "wnews.h"


#define NO_NEWS		1
#define HAVE_NEWS	0


char *Release = VERSION;
char *Version = "@(#) checknews 4.50 (03-Feb-1995)";


char *program;
int opt_n = 0;                          /* "No News" is default         */
int opt_y = 1;                          /* "There is news" is default   */
int opt_q = 0;                          /* be quiet; just an exit value */
int opt_v = 0;                          /* tell which groups have news  */
ACT *active;                            /* in-core "active" file        */


_PRO( unsigned int ng_find, (char *name)				);
_PRO( int chk_news, (char *ng_list)					);


/* Find a newsgroup in the in-core "active" file. */
unsigned int
ng_find(name)
char *name;
{
  register ACT *ap, *bp;

  ap = active;
  bp = active;
  while (ap != (ACT *)NULL) {
	if (!strcmp(ap->group, name)) {
		/*
		 * This is a dirty hack, we just remove the found
		 * newsgroup from the linked list. This should make
		 * it a lot faster.
		 */
		if (ap == active) active = ap->next;
		  else bp->next = ap->next;

		/* Check for validity. */
		if (ap->first >= ap->last) return(0);
		return(ap->last);
	}
	bp = ap;
	ap = ap->next;
  }
  return((unsigned int) 0);
}


/* Check if there is any news pending. */
int
chk_news(ng_list)
char *ng_list;
{
  char buff[1024], fname[128];
  struct passwd *pw;
  register FILE *fp;
  register char *sp, *bp;
  unsigned int seq, act;
  int found;

  /* Open the ACTIVE file for reading. */
  active = act_rd();
  if (active == (ACT *)NULL) {
	logmsg(LOGERR, "cannot open active file\n");
	exit(1);
  }

  /* Find ~/.newsrc */
  pw = getpwuid(getuid());
  if (pw == (struct passwd *)NULL) {
	fputs("checknews: cannot find myself\n", stderr);
	return(ERROR);
  }
  sprintf(fname, "%s/%s", pw->pw_dir, NEWSRC);
  if ((fp = fopen(fname, "r")) == (FILE *)NULL) {
	if (opt_v == 1) fprintf(stderr, "checknews: cannot open(%s)\n", fname);
	return(NO_NEWS);
  }

  /* Now, read the file, and check the numbers. */
  found = 0;
  while (fgets(buff, 1024, fp) != (char *)NULL) {
	if (buff[0] == '0' || buff[0] == '\n') continue;

	/* Look for the end of the newsgroup name. */
	sp = buff;
	while (*sp && *sp != ':' && *sp != '!') sp++;

	/* If it's unsubscribed, skip it. */
	if (*sp == '!') continue;

	/* See if it matches the list we want to check. */
	if (*sp) *sp++ = '\0';
	if (ng_list != (char *)NULL) {
		if (group_match(buff, ng_list) == 0) continue;
	}

	/* If there's a list of articles, take the last number. */
	while(*sp == ' ' || *sp == '\t') sp++;
	if ((bp = strrchr(sp, ',')) != (char *)NULL) sp = ++bp;

	/* if it's a range, take the last number. */
	if ((bp = strchr(sp, '-')) != (char *)NULL) sp = ++bp;
	  else bp = sp;

	/* And read the number. */
	while (*sp && *sp >= '0' && *sp <= '9') sp++;
	*sp = '\0';
	seq = (unsigned int) atol(bp);

	/* See if the number in active was higher than in .newsrc */
	if ((act = ng_find(buff)) > seq) {
		if (opt_v == 1) {
			if (!found++)
				puts("Newsgroup:                             new articles:");
			if ((seq+1)==act) {
				printf("%-30s              %d\n", 
							buff, act);
			} else {
				printf("%-30s         %5u - %d\n",
							buff, seq+1, act);
			}
		} else {
			(void) fclose(fp);
			return(HAVE_NEWS);
		}
	}
	(void)bzero(buff, 1024);
  }
  (void) fclose(fp);
  return(found ? HAVE_NEWS : NO_NEWS);
}


void
usage()
{
  fputs("Usage: checknews [-nqvy] [ -N ng_list ]\n", stderr);
  exit(ERROR);
}


int
main(argc, argv)
int argc;
char *argv[];
{
  register int c;
  int st;
  char *ng_list;

  ng_list = (char *)NULL;               /* all groups by default        */
  program = strrchr(*argv, '/');
  if (program == (char *)NULL) program = *argv;
    else program++;

#ifndef COHERENT
  opterr = 0;
#endif
  while ((c = getopt(argc, argv, "nqvyN:")) != EOF) switch(c) {
	case 'n':
		opt_n = 1;
		break;

	case 'q':
		opt_q = 1;
		break;

	case 'v':
		opt_v = 1;
		break;

	case 'y':
		opt_y = 1;
		break;

	case 'N':
		ng_list = optarg;
		break;

	default:
		usage();
  }

  /* No more arguments allowed. */
  if (optind != argc) usage();

  /* Check the news system. */
  st = NO_NEWS;
  switch(chk_news(ng_list)) {
	case NO_NEWS:
		if (opt_q == 0) {
			if (opt_n == 1) puts("No news.");
		}
		break;

	case HAVE_NEWS:
		if (opt_q == 0) {
			if (opt_y == 1 && opt_v == 0)
					puts("There is news.");
		} else st = HAVE_NEWS;
		break;

	case ERROR:
		st = ERROR;
		break;
  }

  exit(st);
}
