home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
s
/
snws190s.zip
/
SNEWS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-06
|
32KB
|
1,127 lines
/*
SNEWS 1.90α
snews - a simple threaded news reader
Copyright (C) 1991 John McCombs, Christchurch, NEW ZEALAND
john@ahuriri.gen.nz
PO Box 2708, Christchurch, NEW ZEALAND
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 1, as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
See the file COPYING, which contains a copy of the GNU General
Public License.
*/
#include "defs.h"
#include "snews.h"
#include <alloc.h>
#include <ctype.h>
int xfile = FALSE;
INFO my_stuff;
/*------------------------------- main --------------------------------*/
void main(void)
{
ACTIVE *gp, *head;
int done;
printf("loading config... ");
if (load_stuff()) {
printf("loading active... ");
head = load_active_file();
printf("loading read list... ");
load_read_list();
printf("loading history... ");
load_history_list();
done = FALSE;
gp = NULL;
while (!done) {
if ((gp = select_group(head, gp)) != NULL) {
done |= read_group(gp);
} else {
done = TRUE;
}
}
clrscr();
free_hist_list();
save_read_list();
close_active_file();
} else {
fprintf(stderr, "Couldn't find neccessary item in the .rc files\n");
}
}
/*-------------------------- find which group to read -----------------------*/
ACTIVE *select_group(ACTIVE *head, ACTIVE *current)
{
/*
* Present the list of groups, and allow him to move up and down with
* the arrow and PgUp and PgDn keys. 'h' for help, -/+ for searches
*/
ACTIVE *top; /* newsgroup at the top of the page */
ACTIVE *this; /* current newsgroup */
ACTIVE *tmp_ng;
int exit_code; /* why we are exiting the loop */
char sub_tmp[80];
int ch, i, j, articles, unread;
this = (current == NULL) ? head : current;
top = head;
exit_code = 0;
show_groups(&top, this, TRUE);
while (exit_code == 0) {
ch = getch();
switch (ch) {
case 0 :
ch = getch();
switch (ch) {
case Fn1 :
show_help(HELP_GROUP);
show_groups(&top, this, TRUE);
break;
case Fn2 :
show_values();
show_groups(&top, this, TRUE);
break;
case UP_ARR :
if (this->last != NULL) this = this->last;
break;
case DN_ARR :
if (this->next != NULL) this = this->next;
break;
case PGUP :
for (i = 0; i < PAGE_LENGTH; i++) {
if (this->last == NULL) break;
this = this->last;
}
break;
case PGDN :
for (i = 0; i < PAGE_LENGTH; i++) {
if (this->next == NULL) break;
this = this->next;
}
break;
case HOME :
top = this = head;
show_groups(&top, this, TRUE);
break;
case END :
this = head;
while (this->next != NULL)
this = this->next;
break;
}
break;
case 'p' :
strcpy(sub_tmp, "");
post(NULL, this->group, sub_tmp);
show_groups(&top, this, TRUE);
break;
case '?' :
case 'h' :
show_help(HELP_GROUP);
show_groups(&top, this, TRUE);
break;
case 'c' :
mark_group_as_read(this);
show_groups(&top, this, TRUE);
break;
case TAB :
tmp_ng = this->next;
unread = 0;
while (tmp_ng != NULL) {
articles = (int) (tmp_ng->hi_num - tmp_ng->lo_num);
for (j = 0; j < articles; j++) {
if ( *((tmp_ng->read_list)+j) == FALSE)
unread++;
}
if (unread > 0) break;
tmp_ng = tmp_ng->next;
}
if (unread > 0) {
this = tmp_ng;
} else {
message("-- No more articles to read --");
}
break;
case ENTER :
exit_code = EX_DONE;
break;
case ESCAPE :
exit_code = EX_QUIT;
break;
};
if (exit_code == 0)
show_groups(&top, this, FALSE);
}
if (exit_code == EX_DONE)
return(this);
else
return(NULL);
}
/*---------------------------- help screen ----------------------------------*/
void show_help(int h)
{
char *type[] = {"New Group", "Thread", "Article"};
clrscr();
textbackground(headb); textcolor(headf);
clreol();
cprintf(" %s Help (%s)\r\n", type[h], VERSION);
clreol();
textbackground(helpb); textcolor(helpf);
switch (h) {
case HELP_GROUP :
cprintf("\r\n\r\n");
cprintf(" LIST NEWSGROUPS CHOOSING NEWSGROUPS\r\n\r\n");
cprintf(" PgUp move display up one page TAB go to next unread newsgroup\r\n");
cprintf(" PgDn move display down one page ENTER read selected newsgroup\r\n");
cprintf(" Home move to top of list\r\n");
cprintf(" End move to bottom of list\r\n");
cprintf(" \x18 move up one line\r\n");
cprintf(" \x19 move down one line\r\n\r\n");
/* 1 2 */
cprintf(" POST ARTICLE SPECIAL ACTIONS\r\n\r\n");
cprintf(" p post article in newsgroup c mark this newsgroup as read\r\n");
cprintf(" F2 show user values\r\n");
break;
case HELP_THREAD :
/* 1 2 */
cprintf("\r\n\r\n");
cprintf(" LISTING THREADS READING THREADS\r\n\r\n");
cprintf(" PgUp move display up one page TAB read next unread article\r\n");
cprintf(" PgDn move display down one page ENTER read the selected thread\r\n");
cprintf(" Home move to top of list \x1a read the selected thread\r\n");
cprintf(" End move to bottom of list\r\n");
cprintf(" \x18 move up one line\r\n");
cprintf(" \x19 move down one line\r\n\r\n");
cprintf(" MISCELLANEOUS ACTIONS EXTRACT THREADS\r\n\r\n");
cprintf(" p post article in newsgroup s save thread to disk\r\n");
cprintf(" c mark this newsgroup as read w extract article to \\EXTRACT.NWS\r\n");
cprintf(" F2 show user values\r\n");
break;
case HELP_ARTICLES:
cprintf("\r\n\r\n");
cprintf(" READING ARTICLES CHOOSING ARTICLES\r\n\r\n");
cprintf(" PgUp move display up one page TAB read next unread article\r\n");
cprintf(" PgDn move display down one page ENTER read next article\r\n");
cprintf(" Home move to top of article \x1a read next article in thread\r\n");
cprintf(" End move to bottom of article \x1b read prior article in thread\r\n");
cprintf(" \x18 move up one line\r\n");
cprintf(" \x19 move down one line\r\n");
cprintf(" SEND MAIL\r\n");
cprintf(" POST ARTICLE\r\n");
cprintf(" r mail reply to author\r\n");
cprintf(" p post new article R mail reply to someone\r\n");
cprintf(" f post follow-up article m mail article to someone\r\n\r\n");
/* 1 2 */
cprintf(" SPECIAL ACTION EXTRACT ARTICLES\r\n\r\n");
cprintf(" x decode ROT-13 article s save article to file\r\n");
cprintf(" c mark all articles as read w extract article to \\EXTRACT.NWS\r\n");
cprintf(" F2 show user values\r\n");
break;
};
message("-- Press any key to continue --");
getch();
}
/*-------------- show the values of user defined variables -------------*/
void show_values(void)
{
clrscr();
textbackground(headb); textcolor(headf);
clreol();
cprintf(" Pre-set User values (%s)\r\n", VERSION);
clreol();
textbackground(helpb); textcolor(helpf);
cprintf("\r\n\r\n");
cprintf(" User Name: %s@%s (%s)\r\n\r\n",my_stuff.user, my_stuff.my_domain,
my_stuff.my_name);
cprintf(" Local node name: %s\r\n",my_stuff.my_site);
cprintf(" Mail Server: %s\r\n",my_stuff.mail_server);
cprintf(" Organization: %s\r\n\r\n",my_stuff.my_organisation);
cprintf(" Signature File: %s\r\n",my_stuff.signature);
cprintf(" Reply-To: %s\r\n",my_stuff.replyuser);
cprintf(" Aliases file: %s\r\n",my_stuff.alias_file);
cprintf(" File Editor: %s\r\n\r\n",my_stuff.editor);
cprintf(" News Home Directory: %s\r\n",my_stuff.home);
cprintf(" Temporary Directory: %s\r\n",my_stuff.temp_str);
message("-- Press any key to continue --");
getch();
}
/*-------------------- show the list of active groups -----------------------*/
void show_groups(ACTIVE **top, ACTIVE *this, int force)
{
/*
* This routine takes 'top', a pointer to the first line on the screen
* and 'this' a pointer to where we want to be, and updates the screen.
* A maker to this is maintained, and the screen is repainted, where
* necessary
*/
static last_y;
static last_index;
int i, ur;
ACTIVE *that;
/*
* If 'this' is above the 'top' or it is more than a screen length below,
* or'this and 'top' are both zero, ie first time repaint the screen
*/
if ( force || ((*top)->index > this->index) || (this->index - (*top)->index) > PAGE_LENGTH-1) {
clrscr();
textbackground(headb); textcolor(headf);
clreol();
cprintf(" Select Newsgroup (%s) [%ldk]\r\n", VERSION, farcoreleft()/1000);
clreol();
cprintf("\r\n");
clreol();
textbackground(textb); textcolor(textf);
/* now adjust the top */
*top = this;
for (i = 0; i < PAGE_LENGTH/2; i++) {
if ((*top)->last == NULL) break;
*top = (*top)->last;
}
that = *top;
for (i = 0; i < PAGE_LENGTH; i++) {
ur = count_unread_in_group(that);
gotoxy(7, i+4);
cprintf("%4d. %-50s", ((*top)->index)+i, that->group);
if (ur == 0)
cprintf(" ", ur);
else
cprintf(" %4d", ur);
cprintf(" (%d)\r\n", that->hi_num - that->lo_num);
that = that->next;
if (that == NULL) break;
}
last_y = this->index - (*top)->index;
last_index = this->index;
}
gotoxy(5, last_y + PAGE_HEADER);
putch(' ');
last_y += (this->index - last_index);
gotoxy(5, last_y + PAGE_HEADER);
putch('>');
last_index = this->index;
command("ESC=quit TAB=next unread group ENTER=read group F1 or '?'=help");
}
/*--------------------------- process message -------------------------------*/
int read_group(ACTIVE *gp)
{
/*
* We now have newsgroup. Access the directory and try to read
* the newsgroup articles, extracting the headers.
*/
ARTICLE *start;
if (gp->lo_num < gp->hi_num) {
clrscr();
printf(" Select Thread (%s) [%ldk]\n", VERSION, farcoreleft()/1000);
printf("Group: %s ", gp->group);
start = get_headers(gp);
select_thread(gp, start);
free_header(start);
}
return(0);
}
/*-------------------- show the list of active groups -----------------------*/
void show_threads(ACTIVE *gp, ARTICLE **top, ARTICLE *this, int force)
{
/*
* This routine takes 'top', a pointer to the first line on the screen
* and 'this' a pointer to where we want to be, and updates the screen.
* A maker to this is maintained, and the screen is repainted, where
* necessary
*/
static last_y;
static last_index;
int i;
ARTICLE *that;
int unread;
/*
* If 'this' is above the 'top' or it is more than a screen length below,
* or'this and 'top' are both zero, ie first time repaint the screen
*/
if ( force || ((*top)->index > this->index) || (this->index - (*top)->index) > PAGE_LENGTH-1) {
clrscr();
textbackground(headb); textcolor(headf);
clreol();
cprintf(" Select Thread (%s) [%ldk]\r\n", VERSION, farcoreleft()/1000);
clreol();
cprintf("Group: %s\r\n", gp->group);
clreol();
textbackground(textb); textcolor(textf);
/* now adjust the top */
*top = this;
for (i = 0; i < PAGE_LENGTH/2; i++) {
if ((*top)->last == NULL) break;
*top = (*top)->last;
}
that = *top;
for (i = 0; i < PAGE_LENGTH; i++) {
unread = count_unread_in_thread(gp, that),
gotoxy(7, i+4);
if (unread > 0)
cprintf("%4d. %4d %4d %s", ((*top)->index)+i, unread, that->num_articles, that->header);
else
cprintf("%4d. %4d %s", ((*top)->index)+i, that->num_articles, that->header);
that = that->next;
if (that == NULL)
break;
}
last_y = this->index - (*top)->index;
last_index = this->index;
}
gotoxy(5, last_y + PAGE_HEADER);
putch(' ');
last_y += (this->index - last_index);
gotoxy(5, last_y + PAGE_HEADER);
putch('>');
last_index = this->index;
command("ESC=select group TAB=next unread ENTER=next article F1 or '?'=help");
}
/*-------------------------- find which group to read -----------------------*/
void select_thread(ACTIVE *gp, ARTICLE *head)
{
/*
* Present the list of threads, and allow him to move up and down with
* the arrow and PgUp and PgDn keys. 'h' for help, -/+ for searches
*/
ARTICLE *top; /* thread at the top of the page */
ARTICLE *this; /* current thread */
ARTICLE *th;
ART_ID *art;
int exit_code; /* why we are exiting the loop */
char sub_tmp[80];
int ch, i, idx, hit, a_ct;
this = head;
top = head;
exit_code = 0;
show_threads(gp, &top, this, TRUE);
while (exit_code == 0) {
ch = getch();
switch (ch) {
case 0 :
ch = getch();
xfile = FALSE;
switch (ch) {
case Fn1 :
show_help(HELP_THREAD);
show_threads(gp, &top, this, TRUE);
break;
case Fn2 :
show_values();
show_threads(gp, &top, this, TRUE);
break;
case UP_ARR :
if (this->last != NULL) this = this->last;
break;
case DN_ARR :
if (this->next != NULL) this = this->next;
break;
case PGUP :
for (i = 0; i < PAGE_LENGTH; i++) {
if (this->last == NULL) break;
this = this->last;
}
break;
case PGDN :
for (i = 0; i < PAGE_LENGTH; i++) {
if (this->next == NULL) break;
this = this->next;
}
break;
case RIGHT :
read_thread(gp, this, this->art_num, 1);
show_threads(gp, &top, this, TRUE);
break;
case HOME :
top = this = head;
show_threads(gp, &top, this, TRUE);
break;
case END :
this = head;
while (this->next != NULL)
this = this->next;
break;
}
break;
case 's' :
save_thread_to_disk(gp, this);
break;
case 'w' :
xfile = TRUE;
save_thread_to_disk(gp,this);
xfile = FALSE;
break;
case 'p' :
strcpy(sub_tmp, "");
post(NULL, gp->group, sub_tmp);
show_threads(gp, &top, this, TRUE);
break;
case '?' :
case 'h' :
show_help(HELP_THREAD);
show_threads(gp, &top, this, TRUE);
break;
case TAB :
/*
* Go to the next unread article. Work through each
* thread, looking at each article to see if it's been
* read
*/
/* for each thread */
th = this;
hit = FALSE;
while (th != NULL) {
art = th->art_num;
a_ct = 0;
/* for each article */
while (art != NULL) {
idx = (int)(art->id - gp->lo_num - 1);
a_ct++;
if ( *((gp->read_list)+idx) == FALSE) {
hit = TRUE;
break;
}
art = art->next_art;
}
if (hit) break;
th = th->next;
}
if (hit) {
this = th;
read_thread(gp, this, art, a_ct);
show_threads(gp, &top, this, TRUE);
} else {
message("-- No more articles to read --");
}
break;
case 'c' :
mark_group_as_read(gp);
show_threads(gp, &top, this, TRUE);
break;
case ENTER :
read_thread(gp, this, this->art_num, 1);
show_threads(gp, &top, this, TRUE);
break;
case ESCAPE :
exit_code = EX_QUIT;
break;
};
if (exit_code == 0)
show_threads(gp, &top, this, FALSE);
}
}
/*------------------------ save a thread ------------------------------*/
void save_thread_to_disk(ACTIVE *gp, ARTICLE *this)
{
ART_ID *id;
char *fn;
TEXT *tx;
LINE *ln;
int a_ct;
char fnx[80];
int ch;
FILE *tmp;
if (xfile == TRUE) /* extract function */
strcpy(fnx,"\\extract.nws");
else { /* save function */
message("Enter filename? ");
gets(fnx);
}
tmp = NULL;
if (xfile == TRUE) { /* extract function */
if (access(fnx, 0) == 0) {
if ((tmp = fopen(fnx, "at")) == NULL) {
message("*** Cannot open file for appending - "
"please any key to continue ***");
getch();
}
}
else {
if ((tmp = fopen(fnx, "wt")) == NULL) {
message("*** Cannot open file for output - press a key to continue ***");
getch();
}
}
}
else { /* save function */
if (access(fnx, 0) == 0) {
message("File exists - append(y/n)? ");
while (((ch = getch()) != 'y') && (ch != 'n'));
if (ch == 'y') {
if ((tmp = fopen(fnx, "at")) == NULL) {
message("*** Cannot open file for appending - "
"please any key to continue ***");
getch();
}
}
}
else {
if ((tmp = fopen(fnx, "wt")) == NULL) {
message("*** Cannot open file for output - press a key to continue ***");
getch();
}
}
}
if (tmp != NULL) {
fn = make_news_group_name(gp->group);
id = this->art_num;
a_ct = 0;
while (id != NULL) {
if (xfile == TRUE) {
fputs("\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\n",tmp);
}
tx = load_article(fn, id->art_off);
ln = tx->top;
while (ln != NULL) {
fputs(ln->data, tmp);
ln = ln->next;
}
fputs("\n", tmp);
a_ct++;
id = id->next_art;
free_article(tx);
}
fclose(tmp);
}
message("");
}
/*------------------------ read a thread ------------------------------*/
int read_thread(ACTIVE *gp, ARTICLE *this, ART_ID *first, int a_ct)
{
ART_ID *id;
char *fn;
int idx, res;
TEXT *tx;
char author[128], msg_id[128];
CROSS_POSTS *h, *h0;
ACTIVE *gx;
fn = make_news_group_name(gp->group);
id = first;
while (id != NULL) {
tx = load_article(fn, id->art_off);
res = read_article(gp, tx, this->header, a_ct, this->num_articles);
/* mark this article as read */
idx = (int) ((id->id) - gp->lo_num - 1);
*((gp->read_list)+idx) = TRUE;
/* mark the crossposts */
get_his_stuff(tx, author, msg_id);
if ((h0 = look_up_history(msg_id, gp->group)) != NULL) {
h = h0;
while (h != NULL) {
gx = find_news_group(h->group);
if (gx) {
idx = (int) ((h->art_num) - gx->lo_num - 1);
*((gx->read_list)+idx) = TRUE;
}
h = h->next;
}
free_cross_post_list(h0);
}
if (res == EX_QUIT) {
free_article(tx);
break;
}
if (res == EX_NEXT_UNREAD) {
while (id != NULL) {
idx = (int)(id->id - gp->lo_num - 1);
if ( *((gp->read_list)+idx) == FALSE) {
break;
}
a_ct++;
id = id->next_art;
}
if (id == NULL)
message("-- No more articles in thread --");
} else {
if (res == LEFT && id->prev_art) { /* only go back if we can */
a_ct--;
id = id->prev_art;
}
else {
if (res != LEFT) {
a_ct++;
id = id->next_art;
}
}
}
free_article(tx);
}
return(res);
}
/*------------------------- read the headers --------------------------*/
ARTICLE *get_headers(ACTIVE *gp)
{
/*
* Read the files and get the headers
*/
char *fn;
char buf[256], fnx[256], *buf_p;
long g, n_read;
FILE *tmp_file;
ARTICLE *start, *that, *tmp;
ART_ID *art_this, *new;
int ct_art;
n_read = 0;
ct_art = 0;
start = NULL;
fn = make_news_group_name(gp->group);
sprintf(fnx, "%s.IDX", fn);
gotoxy(1,25);
printf("articles processed: ");
if ((tmp_file = fopen(fnx, "rb")) != NULL) {
for (g = gp->lo_num+1; g <= gp->hi_num; g++) {
if ((n_read++ % 10) == 0) {
gotoxy(21,25);
printf("%d", n_read-1);
}
/*
* Read the index
* Search the linked list for the subject
* - allocate a new subject if necessary
* - add to the existing list
*/
if (fgets(buf, 255, tmp_file) == NULL) {
gotoxy(1,25);
fprintf(stderr, "\nsnews: index file is corrupt\n");
exit(1);
}
/* check all is in sync */
if (g != atol(buf+9)) {
gotoxy(1,25);
fprintf(stderr, "\nsnews: article %ld found when %ld expected\n", atol(buf+9), g);
exit(1);
}
/* skip the two eight digit numbers and the 9 and the spaces */
buf_p = buf+28;
eat_gunk(buf_p);
tmp = start;
while (tmp != NULL) {
if (stricmp(buf_p, tmp->header) == 0)
break;
tmp = tmp->next;
}
if (tmp != NULL) {
/* allocate new article number */
new = xmalloc(sizeof (ART_ID));
new->id = g;
new->art_off = atol(buf);
new->next_art = NULL;
new->prev_art = NULL;
tmp->num_articles++;
/* place it at the end */
art_this = tmp->art_num;
while (art_this->next_art != NULL) {
art_this = art_this->next_art;
}
art_this->next_art = new;
new->prev_art = art_this;
}
else {
/* not found - allocate new thread */
if (start == NULL) {
start = that = xmalloc(sizeof (ARTICLE));
start->last = NULL;
start->next = NULL;
start->index = ct_art;
} else {
ct_art++;
that->next = xmalloc(sizeof (ARTICLE));
that->next->last = that;
that = that->next;
that->next = NULL;
that->index = ct_art;
}
/* store article data */
strcpy(that->header, buf_p);
that->num_articles = 1;
that->art_num = xmalloc(sizeof (ART_ID));
that->art_num->next_art = NULL;
that->art_num->prev_art = NULL;
that->art_num->id = g;
that->art_num->art_off = atol(buf);
}
that->next = NULL;
}
fclose(tmp_file);
}
else {
gotoxy(1,25);
fprintf(stderr, "\nsnews: can't open index file %s\n", fnx);
exit(1);
}
return(start);
}
/*------------------------ clean up subject line ----------------------------*/
void eat_gunk(char *buf)
{
/*
* This routine take the header line, and strips the
* word header word, 'Re:', and any extra blanks, trim to 59 chars
*/
char *p = buf;
buf[58] = 0;
while (*p && isspace(*p)) p++;
while (*p && !strnicmp(p, "re:", 3)) {
p += 3;
while (*p && isspace(*p)) p++;
}
if (!p)
strcpy(buf, "<no subject>");
else
strcpy(buf, p);
p = buf + strlen(buf) - 1;
while (*p && (*p == '\n' || *p == '\t' || *p == '\r'))
p--;
p++; *p = '\0';
}
/*-------------------- release the subject structures ---------------------*/
void free_header(ARTICLE *start)
{
/*
* Work our way through the subject structure releasing all the
* memory
*/
ARTICLE *a, *t;
ART_ID *u, *v;
a = start;
while (a != NULL) {
u = a->art_num;
while (u != NULL) {
v = u->next_art;
free(u);
u = v;
}
t = a->next;
free(a);
a = t;
}
}
/*------------------- count unread articles in a thread --------------------*/
int count_unread_in_thread(ACTIVE *gp, ARTICLE *a)
{
/*
* Take the thread 'a' for the given group 'gp' and return the number
* of unread articles
*/
ART_ID *id;
int ct, idx;
ct = 0;
id = a->art_num;
while (id != NULL) {
idx = (int)(id->id - gp->lo_num - 1);
if (*((gp->read_list)+idx) == FALSE)
ct++;
id = id->next_art;
}
return(ct);
}
/*------------------- count unread articles in a group --------------------*/
int count_unread_in_group(ACTIVE *gp)
{
/*
* Take the thread 'a' for the given group 'gp' and return the number
* of unread articles
*/
int articles, ct, i;
ct = 0;
articles = (int)(gp->hi_num - gp->lo_num);
for (i = 0; i < articles; i++) {
if (*((gp->read_list)+i) == FALSE)
ct++;
}
return(ct);
}
/*------------------- count unread articles in a group --------------------*/
void mark_group_as_read(ACTIVE *gp)
{
/*
* Take the thread 'a' for the given group 'gp' and return the number
* of unread articles
*/
int articles, i, ch;
message("Mark all articles as read (y/n)? ");
while (((ch = getch()) != 'y') && (ch != 'n') && (ch != ESCAPE));
if (ch == 'y') {
articles = (int)(gp->hi_num - gp->lo_num);
for (i = 0; i < articles; i++)
*((gp->read_list)+i) = TRUE;
}
}
/*-------------------------- status message ---------------------------------*/
void message(char *msg)
{
int x;
x = 40 - (strlen(msg)/2);
gotoxy(1,24);
textbackground(msgb); textcolor(msgf);
clreol();
gotoxy(x,24);
cprintf("%s", msg);
textbackground(textb); textcolor(textf);
}
/*-------------------------- status message ---------------------------------*/
void lmessage(char *msg)
{
gotoxy(1,24);
textbackground(msgb); textcolor(msgf);
clreol();
cprintf("%s", msg);
textbackground(textb); textcolor(textf);
}
/*-------------------------- status message ---------------------------------*/
void command(char *msg)
{
int x;
x = 40 - (strlen(msg)/2);
gotoxy(1,25);
textbackground(msgb); textcolor(msgf);
clreol();
gotoxy(x,25);
cprintf(msg);
textbackground(textb); textcolor(textf);
}
/* end */