home *** CD-ROM | disk | FTP | other *** search
- /*
-
- 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;
- }
-