home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Professional
/
OS2PRO194.ISO
/
os2
/
com
/
utils
/
smplnews
/
article.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-02
|
23KB
|
837 lines
/*
SNEWS 2.0
news - routines to read and display an article
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 <process.h>
#include "defs.h"
#include "snews.h"
/*------------------------- recognize address ------------------------------*/
char *plain_address(char *raw)
{
char *ptr = raw, *end;
while (*ptr && !isalnum(*ptr)) {
while (isspace(*ptr)) ptr++;
if (isalnum(*ptr))
break;
if (*ptr == '(') {
for (ptr++; *ptr && *ptr != ')'; ptr++);
if (*ptr == ')') ptr++;
}
else if (*ptr == '"') {
for (ptr++; *ptr && *ptr != '"'; ptr++);
if (*ptr == '"') ptr++;
}
else if (*ptr == '<') {
ptr++;
if ((end = strchr(ptr, '>')) != NULL)
*end = 0;
}
else
ptr++;
}
if ((end = strchr(ptr, ' ')) != NULL)
*end = 0;
if ((end = strchr(ptr, '\t')) != NULL)
*end = 0;
if ((end = strchr(ptr, '\n')) != NULL)
*end = 0;
return ptr;
}
/*------------------------- read in an article -----------------------------*/
TEXT *load_article(char *fnx, long offset)
{
/*
* Open the file and read it. Save the author and organisation
* fill in the structures
*/
FILE *tmp_file;
char lnbuf[MAXLINE];
TEXT *tx;
LINE *ln, *lz;
int ct, i;
tx = NULL;
ct = 0;
if ((tmp_file = flockopen(fnx, "rb")) != NULL) {
setvbuf(tmp_file, iobuf, _IOFBF, IOBUFSIZE);
fseek(tmp_file, offset, SEEK_SET);
tx = xmalloc(sizeof(TEXT));
tx->top = NULL;
tx->start = NULL;
tx->subject = NULL;
tx->follow_up = NULL;
tx->author = NULL;
tx->organisation = NULL;
while (fgets(lnbuf, sizeof(lnbuf) - 1, tmp_file) != NULL) {
lnbuf[sizeof(lnbuf) -1] = 0;
if (strncmp(lnbuf, "@@@@END", 7) == 0) break;
/* is it the first line - if so init the TEXT structure */
if (ct == 0) {
ln = xmalloc(sizeof(LINE));
ln->last = NULL;
tx->top = ln;
} else {
lz = ln;
ln->next = xmalloc(sizeof(LINE));
ln = ln->next;
ln->last = lz;
}
ln->index = ct;
ln->data = xmalloc(strlen(lnbuf) + 1);
strcpy(ln->data, lnbuf);
if ((strlen(lnbuf) == 1) && (tx->start == NULL))
tx->start = ln;
ct++;
/* save the header info */
if ((tx->start == NULL) && (strncmp("From:", lnbuf, 5) == 0)) {
strcpy(lnbuf, plain_address(lnbuf + 5));
tx->author = xmalloc(strlen(lnbuf) + 1);
strcpy(tx->author, lnbuf);
}
if ((tx->start == NULL) &&
((strncmp("Organisation:", lnbuf, 13) == 0) ||
(strncmp("Organization:", lnbuf, 13) == 0))) {
lnbuf[strlen(lnbuf) - 1] = 0;
tx->organisation = xmalloc(strlen(lnbuf + 14) + 1);
strcpy(tx->organisation, lnbuf + 14);
}
if ((tx->start == NULL) && (strncmp("Subject:", lnbuf, 8) == 0)) {
lnbuf[strlen(lnbuf) - 1] = 0;
tx->subject = xmalloc(strlen(lnbuf + 9) + 1);
strcpy(tx->subject, lnbuf + 9);
}
if ((tx->start == NULL) && (strncmp("Followup-To:", lnbuf, 12) == 0)) {
lnbuf[strlen(lnbuf) - 1] = 0;
tx->follow_up = xmalloc(strlen(lnbuf + 13) + 1);
strcpy(tx->follow_up, lnbuf + 13);
}
}
ln->next = NULL;
tx->lines = ct;
fclose(tmp_file);
}
return(tx);
}
/*---------------------- deallocate article memory ------------------------*/
void free_article(TEXT *t)
{
LINE *l, *k;
l = t->top;
while (l != NULL) {
k = l;
l = l->next;
free(k->data);
free(k);
}
if (t->subject)
free(t->subject);
if (t->follow_up)
free(t->follow_up);
if (t->author)
free(t->author);
if (t->organisation)
free(t->organisation);
free(t);
}
/*---------------------------- display a line -----------------------------*/
void putline(char *line, int margin)
{
char buf[MAXLINE];
int length;
strcpy(buf, line);
expand_tabs(buf, MAXLINE);
length = strlen(buf);
if ( length > margin ) {
if ( length > margin + _columns )
printf("%-*.*s$", _columns - 1, _columns - 1, buf + margin);
else {
puts(buf + margin);
if ( length - margin < _columns )
clreol();
}
}
else
clreol();
}
/*---------------------------- read an article ----------------------------*/
int read_article(ACTIVE *gp, TEXT *tx, int a_ct, int of_ct)
{
/*
* This routine alloas the user to read an article
*/
LINE *this, *tmp; /* current thread */
int exit_code; /* why we are exiting the loop */
char buf[MAXLINE];
int ch, i, maxx, margin, newmargin;
this = tx->start;
if (this->next != NULL)
this = this->next;
exit_code = 0;
margin = 0;
show_article(gp, tx, this, a_ct, of_ct, margin);
while ((exit_code == 0) || (exit_code == EX_DUMMY)) {
exit_code = 0;
ch = getch();
switch (ch) {
case 0 :
case 0xE0 :
ch = getch();
switch (ch) {
case F1 :
show_help(HELP_ARTICLES);
break;
case L_ARR :
if ( margin == 0 )
exit_code = EX_DUMMY;
else
margin = max(0, margin - 4);
break;
case C_L_ARR :
if ( margin == 0 )
exit_code = EX_DUMMY;
else
margin = 0;
break;
case R_ARR :
tmp = this;
newmargin = margin;
for (i = 0; i < PAGE_LENGTH-1; i++) {
strcpy(buf, tmp->data);
expand_tabs(buf, MAXLINE);
newmargin = max(newmargin, strlen(buf));
tmp = tmp->next;
if (tmp == NULL) break;
}
if ( margin >= newmargin - _columns )
exit_code = EX_DUMMY;
else
margin += 4;
break;
case C_R_ARR :
tmp = this;
newmargin = margin;
for (i = 0; i < PAGE_LENGTH-1; i++) {
strcpy(buf, tmp->data);
expand_tabs(buf, MAXLINE);
newmargin = max(newmargin, strlen(buf));
tmp = tmp->next;
if (tmp == NULL) break;
}
newmargin = ((newmargin - 1) / 4 + 1) * 4;
if ( newmargin == margin + _columns )
exit_code = EX_DUMMY;
else
margin = newmargin - _columns;
break;
case UP_ARR :
if (this->last != NULL) {
this = this->last;
gotoxy(1,TEXT_LINE);
insline();
putline(this->data, margin);
}
exit_code = EX_DUMMY;
break;
case DN_ARR :
if (this->next != NULL &&
(this->index + PAGE_LENGTH < tx->lines ||
this->index <= tx->start->index)) {
this = this->next;
gotoxy(1,TEXT_LINE);
delline();
gotoxy(1,TEXT_LINE+PAGE_LENGTH-1);
tmp = this;
for (i = 0; i < PAGE_LENGTH-1; i++) {
tmp = tmp->next;
if (tmp == NULL) break;
}
if (tmp)
putline(tmp->data, margin);
}
exit_code = EX_DUMMY;
break;
case HOME :
tmp = this;
this = tx->start;
if (this->next != NULL)
this = this->next;
if (this == tmp)
exit_code = EX_DUMMY;
break;
case END :
tmp = this;
this = tx->start;
while (this->next != NULL)
this = this->next;
for (i = 0; i < PAGE_LENGTH-1; i++) {
if (this->last == NULL) break;
if (tx->start->next && this == tx->start->next)
break;
this = this->last;
}
if (this == tmp)
exit_code = EX_DUMMY;
break;
case PGUP :
if ( this->last == NULL )
exit_code = EX_DUMMY;
else
for (i = 0; i < PAGE_LENGTH-1; i++) {
if (this->last == NULL) break;
this = this->last;
}
break;
case PGDN :
if ( this->next == NULL )
exit_code = EX_DUMMY;
else {
maxx = tx->lines - this->index - PAGE_LENGTH;
maxx = min(maxx, PAGE_LENGTH - 1);
maxx = max(maxx, tx->start->index + 1 - this->index);
if ( maxx <= 0 )
exit_code = EX_DUMMY;
else
for (i = 0; i < maxx; i++) {
if (this->next == NULL) break;
this = this->next;
}
}
break;
default:
exit_code = EX_DUMMY;
break;
}
break;
case 'p' :
case 'P' :
post(NULL, gp->group);
break;
case 'f' :
case 'F' :
if (!tx->follow_up || strcmp(tx->follow_up, "") == 0)
post(tx, gp->group);
else
post(tx, tx->follow_up);
break;
case 'r' :
case 'R' :
reply_to_article(tx);
break;
case 'm' :
case 'M' :
mail_to_someone(tx);
break;
case 's' :
case 'S' :
save_to_disk(tx);
break;
case 'x' :
case 'X' :
rot13(tx);
break;
case 'h' :
case 'H' :
show_help(HELP_ARTICLES);
break;
case TAB :
exit_code = EX_NEXT_UNREAD;
break;
case ENTER :
exit_code = EX_NEXT;
break;
case BACKSP :
exit_code = EX_PREVIOUS;
break;
case '+' :
case '/' :
exit_code = EX_SEARCH_FORW;
break;
case '-' :
case '?' :
exit_code = EX_SEARCH_BACKW;
break;
case ESCAPE :
exit_code = EX_QUIT;
break;
default:
exit_code = EX_DUMMY;
break;
};
if (exit_code == 0)
show_article(gp, tx, this, a_ct, of_ct, margin);
else {
gotoxy(_columns - 16,2);
textbackground(LIGHTGRAY); textcolor(BLACK);
sprintf(buf, "Line %d of %d", this->index + 1, tx->lines);
printf("%17s", buf);
textbackground(BLACK); textcolor(LIGHTGRAY);
}
}
return(exit_code);
}
/*-------------------- show the list of active groups -----------------------*/
void show_article(ACTIVE *gp, TEXT *tx, LINE *this, int a_ct,
int of_ct, int margin)
{
/*
* This routine show a page of an article
*/
int i, length;
char buf[256], buf2[32];
gotoxy(1,1);
textbackground(LIGHTGRAY); textcolor(BLACK);
sprintf(buf2, "Article %d of %d", a_ct, of_ct);
printf("Group: %-*.*s %18s", _columns - 27, _columns - 27,
gp->group, buf2);
gotoxy(1,2);
strcpy(buf, tx->author ? tx->author : "<unknown>");
if (tx->organisation) {
strcat(buf, "; ");
strcat(buf, tx->organisation);
}
sprintf(buf2, "Line %d of %d", this->index + 1, tx->lines);
printf("From: %-*.*s %17s", _columns - 25, _columns - 25, buf, buf2);
gotoxy(1,3);
sprintf(buf2, margin ? ">%d" : "", margin);
printf("Subject: %-*.*s %4s", _columns - 14, _columns - 14,
tx->subject, buf2);
textbackground(BLACK); textcolor(LIGHTGRAY);
for (i = 0; i < PAGE_LENGTH; i++) {
if (this == NULL) break;
gotoxy(1, i+TEXT_LINE);
putline(this->data, margin);
this = this->next;
}
if ( i < PAGE_LENGTH ) {
gotoxy(1, i+TEXT_LINE);
clreos();
}
message("ESC=select thread TAB=next unread ENTER=next F1=help");
}
/*-------------------------- save article --------------------------------*/
void save_to_disk(TEXT *tx)
{
/*
* This routine saves an article to disk, appending if necessary
*/
FILE *tmp = NULL;
LINE *ln;
char fn[256];
int ch;
time_t now;
struct tm *tmnow;
char timestr[64];
lmessage("Enter filename? ");
gets(fn);
if (access(fn, 0) == 0) {
message("File exists - append(y/n)? ");
while (((ch = getch()) != 'y') && (ch != 'n'));
if (ch == 'y') {
if ((tmp = fopen(fn, "at")) == NULL) {
message("*** cannot open file for appending - "
"press any key ***");
getch();
}
}
} else {
if ((tmp = fopen(fn, "wt")) == NULL) {
message("*** cannot open file for output - press any key ***");
getch();
}
setvbuf(tmp, iobuf, _IOFBF, IOBUFSIZE);
}
if (tmp != NULL) {
time(&now);
tmnow = localtime(&now);
strftime(timestr, sizeof(timestr), "%a %b %d %H:%M:%S %z %Y", tmnow);
ln = tx->top;
while (ln != NULL && strncmp(ln->data, "Path: ", 6)) {
ln = ln->next;
}
strcpy(fn, ln->data + 6);
for ( ch = strlen(fn); fn[ch - 1] == '\n' || fn[ch - 1] == '\r'; ch--)
fn[ch - 1] = 0;
fprintf(tmp, "From %s %s\n", fn, timestr);
ln = tx->top;
while (ln != NULL) {
fputs(ln->data, tmp);
ln = ln->next;
}
fclose(tmp);
}
}
/*-------------------------- reply to article ---------------------------*/
void reply_to_article(TEXT *tx)
{
/*
* Mail reply to article
*/
#ifdef INCLUDE_SIG
FILE *sig;
char sig_fn[80];
#endif
FILE *tmp;
LINE *ln;
int ch;
char fn[256];
char buf[256];
char author[80], msg_id[MAXLINE];
char *mailer = getenv("MAILER");
if (mailer == NULL)
mailer = "mail";
strcpy(fn, my_stuff.news_dir);
strcat(fn, "letter");
unlink(fn);
if ((tmp = fopen(fn, "wt")) != NULL) {
get_his_stuff(tx, author, msg_id);
/* add the quoted message */
message("Quote article (y/n)? ");
while (((ch = getch()) != 'y') && (ch != 'n'));
if (ch == 'y') {
fprintf(tmp, "In article %s you write:\n", msg_id);
ln = tx->start;
while (ln != NULL) {
fprintf(tmp, "> %s", ln->data);
ln = ln->next;
}
}
#ifdef INCLUDE_SIG
/* append the signature if there is one */
strcpy(sig_fn, my_stuff.home);
strcat(sig_fn, my_stuff.signature);
if ((sig= fopen(sig_fn, "rt")) != NULL) {
while (fgets(buf, 79, sig) != NULL)
fputs(buf, tmp);
fclose(sig);
}
#endif
fclose(tmp);
sprintf(buf, my_stuff.editor, fn);
system(buf);
sprintf(buf, "Send message to %s (y/n)? ", author);
message(buf);
while (((ch = getch()) != 'y') && (ch != 'n'));
gotoxy(1,PAGE_SIZE);
clreol();
strcpy(msg_id, tx->subject);
eat_gunk(msg_id);
if (ch == 'y') {
sprintf(buf, "%s -s \"Re: %s\" %s <%s >nul 2>&1",
mailer, msg_id, author, fn);
system(buf);
}
/* unlink(fn); /* keep it around like rn */
} else {
message("*** cannot open temp file - press any key ***");
getch();
}
}
/*-------------------------- reply to article ---------------------------*/
void mail_to_someone(TEXT *tx)
{
/*
* Mail this article to someone
*/
FILE *tmp;
LINE *ln;
int ch;
char fn[256];
char buf[256], who[80];
char *subj = tx->subject ? tx->subject : "No subject";
sprintf(fn, "%s\\snews.tmp", my_stuff.temp_name);
if ((tmp= fopen(fn, "wt")) != NULL) {
lmessage("Mail this article to? ");
gets(who);
fprintf(tmp, "Resent-From: %s@%s (%s)\n",
my_stuff.user, my_stuff.my_domain, my_stuff.my_name);
fprintf(tmp, "Resent-To: %s\n", who);
ln = tx->top;
while (ln != NULL) {
fputs(ln->data, tmp);
ln = ln->next;
}
fclose(tmp);
message("Edit outgoing message (y/n)? ");
while (((ch = getch()) != 'y') && (ch != 'n'));
if (ch == 'y') {
sprintf(buf, my_stuff.editor, fn);
system(buf);
}
sprintf(buf, "Mail article to %s (y/n)? ", who);
message(buf);
while (((ch = getch()) != 'y') && (ch != 'n'));
if (ch == 'y') {
sprintf(buf, "rmail -t <%s 2>nul", fn);
system(buf);
}
unlink(fn);
} else {
message("*** cannot open temp file - press any key ***");
getch();
}
}
/*----------------------- get stuf off article header --------------------*/
void get_his_stuff(TEXT *tx, char *author, char *msg_id)
{
/*
* Retrieve the author and msg_id from the article
*/
LINE *ln;
char *p;
char buf[MAXLINE];
char *null_name = {" ** none ** "};
strcpy(author, null_name);
strcpy(msg_id, " <none> ");
ln = tx->top;
while (ln != NULL) {
if (strlen(ln->data) < 2) break;
strcpy(buf, ln->data);
p = strtok(buf, " :\n\r");
p = strtok(NULL, " :\n\r");
if (strnicmp(ln->data, "Message-ID:", 11) == 0) {
strcpy(msg_id, p);
}
if ((strnicmp(ln->data, "From:", 5) == 0) &&
(strcmp(author, null_name) == 0)) {
strcpy(author, plain_address(ln->data+5));
}
if (strnicmp(ln->data, "Reply-to:", 9) == 0) {
strcpy(author, plain_address(ln->data+9));
}
ln = ln->next;
}
}
/*--------------------------- rot 13 the article ------------------------*/
void rot13(TEXT *tx)
{
LINE *ln;
int i, c;
ln = tx->start;
while (ln != NULL) {
for (i = 0; i < strlen(ln->data); i++) {
c = *((ln->data)+i);
if ((c >= 'A') && (c <= 'Z')) {
*((ln->data)+i) = (((c-'A') + 13) % 26) + 'A';
} else {
if ((c >= 'a') && (c <= 'z')) {
*((ln->data)+i) = (((c-'a') + 13) % 26) + 'a';
}
}
}
ln = ln->next;
}
}
/*--------------------------- expand the tabs ----------------------------*/
void expand_tabs(char *buf, int max_len)
{
int l, k;
char tmp[MAXLINE], *p, *t;
p = buf;
t = &tmp[0];
l = 0;
while ((*p != '\x00') && (l < max_len)) {
if (*p != '\x09') {
*t = *p;
t++;
p++;
l++;
} else {
p++;
k = ((l / 8) + 1) * 8;
for ( ; l < k ; l++) {
*t = ' ';
t++;
if (l >= max_len) break;
}
}
}
*t = '\x00';
strcpy(buf, tmp);
l = strlen(buf);
if (buf[l - 1] == '\n')
buf[l - 1] = 0;
}