home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Beijing Paradise BBS Backup
/
PARADISE.ISO
/
software
/
BBSDOORW
/
SNWS191S.ZIP
/
ACTIVE.C
next >
Wrap
C/C++ Source or Header
|
1993-08-23
|
24KB
|
841 lines
/*
SNEWS 1.91
active - routines to manipulate the active, .nrc and .rc files
Copyright (C) 1991 John McCombs, Christchurch, NEW ZEALAND
john@ahuriri.gen.nz
PO Box 2708, Christchurch, NEW ZEALAND
Modifications copyright (C) 1993 Daniel Fandrich
<dan@fch.wimsey.bc.ca> or CompuServe 72365,306
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.
Source is formatted with a tab size of 4.
*/
#define ACTIVE_C
#include "defs.h"
#include <alloc.h>
#include <ctype.h>
extern INFO my_stuff;
int headf = BLACK;
int headb = LIGHTGRAY;
int textf = LIGHTGRAY;
int textb = BLACK;
int helpf = LIGHTGRAY;
int helpb = BLACK;
int msgf = BLACK;
int msgb = LIGHTGRAY;
volatile int break_hit = 0; /* incremented when control-break is hit */
/*
* These private variables are used to do all the i/o on the active
* file.
*/
static FILE *active_file;
static ACTIVE *local_head;
/*--------------------------- load the active file --------------------------*/
ACTIVE *load_active_file(void)
{
/*
* This routine opens the active file. It reads the data, allocating
* ACTIVE elements in a linked list. Returns a pointer to the head of
* the linked list.
*/
char fn[80], buf[81];
char *p;
ACTIVE *this = NULL, *head = NULL;
long posn = 0;
int ct = 0;
int ct_gp = 0;
/* open the file */
strcpy(fn, my_stuff.news_dir);
strcat(fn, "active");
if ((active_file = fopen(fn, "r+b")) == NULL) {
fprintf(stderr, "cannot open %s\n", fn);
exit(1);
}
/* read and store */
while (fgets(buf, 80, active_file) != NULL) {
/* exit on ^Z on column 1 */
if (buf[0] == '\x1A')
break;
ct++;
if (strlen(buf) > 0) {
if (head == NULL) {
head = this = xmalloc(sizeof (ACTIVE));
head->last = NULL;
head->index = ct_gp;
} else {
ct_gp++;
this->next = xmalloc(sizeof (ACTIVE));
this->next->last = this;
this = this->next;
this->index = ct_gp;
}
if ((this) == NULL) {
fprintf(stderr, "cannot allocate memory for active list\n");
exit(1);
}
if ((p = strtok(buf, " ")) == NULL) {
fprintf(stderr, "active file corrupt at line %d #1\n", ct);
exit(1);
}
strcpy(this->group, p);
this->local = isupper(this->group[0]); /* is group local? */
this->group[0] = tolower(this->group[0]);
if ((p = strtok(NULL, " ")) == NULL) {
fprintf(stderr, "active file corrupt at line %d #2\n", ct);
exit(1);
}
strcpy(this->gp_file, p);
if ((p = strtok(NULL, " ")) == NULL) {
fprintf(stderr, "active file corrupt at line %d #3\n", ct);
exit(1);
}
this->lo_num = atol(p);
if ((p = strtok(NULL, " ")) == NULL) {
fprintf(stderr, "active file corrupt at line %d #4\n", ct);
exit(1);
}
this->hi_num = atol(p);
if ((p = strtok(NULL, " ")) == NULL) {
fprintf(stderr, "active file corrupt at line %d #5\n", ct);
exit(1);
}
this->post = tolower(*p);
this->num_pos = posn;
this->read_list = NULL;
}
posn = ftell(active_file);
}
if (this)
this->next = NULL;
local_head = head;
return(head);
}
/*------------------------- close the active file ---------------------------*/
void close_active_file(void)
{
/*
* Close the active file and deallocate the linked list
*/
ACTIVE *this;
this = local_head;
while (this != NULL) {
local_head = this;
this = this->next;
free(local_head);
}
fclose(active_file);
}
/*------------------------- close the active file ---------------------------*/
void close_active(void)
{
/*
* Close the active file
*/
fclose(active_file);
}
/*------------------------- check group in post list -------------------------*/
int check_valid_post_group(char *ng)
{
/*
* Check a string as a valid newsgroup name. Returns TRUE if found and
* posting is allowed.
*
* Note: this should be changed to return 1 if posting is allowed,
* 0 if it is not, and -1 if the group is moderated.
*/
ACTIVE *this = local_head;
while (this != NULL) {
if (strcmp(ng, this->group) == 0)
switch (this->post) {
case 'y': return TRUE;
/* case 'm': return -1; */
case 'n':
default: return FALSE;
}
this = this->next;
}
return (FALSE);
}
/*-------------------- see if newsgroup is local only -----------------------*/
int is_local_group(char *ng)
{
ACTIVE *this = local_head;
while (this != NULL) {
if (strcmp(ng, this->group) == 0)
return(this->local);
this = this->next;
}
return (TRUE); /* return TRUE if group name is not found */
}
/*-------------------- find a newsgroup in active list ----------------------*/
ACTIVE *find_news_group(char *group)
{
/*
* This routine searches the active structure for the specified
* newsgroup, and returns a pointer to the entry, or to group
* junk if not found. The search for junk is made via a recursive
* call. Fatal if junk not found
*/
ACTIVE *this;
this = local_head;
while ((this != NULL) && (stricmp(group, this->group) != 0)) {
this = this->next;
}
if (this == NULL) {
if (stricmp(group, "junk") != 0) {
this = find_news_group("junk");
} else {
fprintf(stderr, "active file must have newsgroup junk\n");
exit(1);
}
}
return(this);
}
/*-------------------------- update active file ---------------------------*/
void update_active_entry(ACTIVE *a)
{
/*
* This routine takes a pointer to an active entry and updates
* its data on disk
*/
char buf[(ACTIVE_NUM_LEN*2) + 2];
int n;
long where;
sprintf(buf, "%08ld %08ld", a->lo_num, a->hi_num);
n = (ACTIVE_NUM_LEN*2) + 1;
where = a->num_pos + strlen(a->group) + 1 + strlen(a->gp_file) + 1;
fseek(active_file, where, SEEK_SET);
if (fwrite(buf, 1, n, active_file) != n) {
fprintf(stderr, "active file update failed for %s\n", a->group);
exit(1);
}
fflush(active_file);
}
/*------------------- make newsgroup name and directory --------------------*/
char *make_news_group_name(char *ng)
{
/*
* This routine takes the newsgroup name, replaces the '.' with
* '\' and creates the directory if none exists. The returned name
* has a trailing '\'
*/
static char fn[512];
ACTIVE *tmp;
tmp = find_news_group(ng);
sprintf(fn, "%snewsbase\\%s", my_stuff.news_dir, tmp->gp_file);
return(&fn[0]);
}
/*-------------------------- save the seen list -------------------------*/
void load_read_list(void)
{
/*
* Load the user's list of seen articles
*/
FILE *tmp_file;
ACTIVE *act;
int i, continue_flag;
int articles;
char *a, buf[256], *p, real_name[80];
/* allocate the arrays and set to unread, ie FALSE */
act = local_head;
while (act != NULL) {
articles = (int)(act->hi_num - act->lo_num);
if (articles > 0) {
a = act->read_list = xmalloc(articles * sizeof(char));
for (i = 0; i < articles; i++) {
*(a+i) = FALSE;
}
} else {
act->read_list = NULL;
}
act = act->next;
}
/* read and process the file - if not present, just carry on */
/* strcpy(buf, my_stuff.news_dir);
strcat(buf, my_stuff.user);
strcat(buf, ".nrc");
*/
strcat(strcpy(buf, my_stuff.home), "snews.nrc");
if ((tmp_file = fopen(buf, "rt")) != NULL) {
continue_flag = FALSE;
while (fgets(buf, 255, tmp_file) != NULL) {
p = strtok(buf, " \n\r");
if (!continue_flag) {
strcpy(real_name, p);
act = find_news_group(p);
articles = (int)(act->hi_num - act->lo_num);
/* if no articles or unknown group eat the rest */
p = strtok(NULL, " \n\r");
}
/* scan the rest of the line getting numbers and setting flags */
continue_flag = FALSE;
while (p != NULL) {
/* check for continuation backslash */
if (*p != '\\') {
i = (int) (atol(p) - (act->lo_num + 1));
if ((i >= 0) && (i < articles) &&
((stricmp(act->group, "junk") != 0) ||
(stricmp(real_name, "junk") == 0))) {
*((act->read_list)+i) = TRUE;
}
} else {
continue_flag = TRUE;
break;
}
p = strtok(NULL, " \n\r");
}
}
fclose(tmp_file);
}
}
/*-------------------------- load the seen list -------------------------*/
void save_read_list(void)
{
/*
* Save the user's list of read articles and deallocate storage
*/
FILE *tmp_file;
ACTIVE *act;
int i, articles, ct;
char buf[256];
/* open the file */
/* strcpy(buf, my_stuff.news_dir);
strcat(buf, my_stuff.user);
strcat(buf, ".nrc");
*/
strcat(strcpy(buf, my_stuff.home), "snews.nrc");
if ((tmp_file = fopen(buf, "wt")) == NULL) {
fprintf(stderr, "can't open user's rc file for output\n");
exit(1);
}
/* write out the lists and deallocate the arrays */
act = local_head;
while (act != NULL) {
articles = (int)(act->hi_num - act->lo_num);
if (articles > 0) {
fprintf(tmp_file, "%s ", act->group);
ct = 0;
if (act->read_list != NULL) {
for (i = 0; i < articles; i++) {
if(*((act->read_list)+i)) {
ct++;
fprintf(tmp_file, "%d ", i+act->lo_num+1);
if ((ct % 10) == 0)
fprintf(tmp_file, "\\ \n");
}
}
}
fprintf(tmp_file, "\n");
if (act->read_list != NULL) {
free(act->read_list);
}
}
act = act->next;
}
fclose(tmp_file);
}
/*------------------------- set colors -----------------------------------*/
void set_colors(char *keyword, char *value)
{
static char *colors[] = {"bla","blu","gre","cya","red","mag","yel","whi"};
int color = 0,
i = 0;
char *f = NULL;
if (value)
strlwr(value);
f = strtok(value,"\0"); /* does this do anything? [df] */
while (isspace(*f)) f++;
for (i = 0; (i < 8) && (strncmp(colors[i],f,3) != 0); i++)
/* empty loop */ ;
color = (i < 8) ? i : 0;
color |= (strchr(f, '+') != NULL) ? 8 : 0;
helpf = (strncmp("helpf", keyword, 5)) ? helpf : (unsigned char) color;
helpb = (strncmp("helpb", keyword, 5)) ? helpb : (unsigned char) color;
textf = (strncmp("textf", keyword, 5)) ? textf : (unsigned char) color;
textb = (strncmp("textb", keyword, 5)) ? textb : (unsigned char) color;
headf = (strncmp("headf", keyword, 5)) ? headf : (unsigned char) color;
headb = (strncmp("headb", keyword, 5)) ? headb : (unsigned char) color;
msgf = (strncmp("msgf", keyword, 4)) ? msgf : (unsigned char) color;
msgb = (strncmp("msgb", keyword, 4)) ? msgb : (unsigned char) color;
}
/*------------------------- load UUPC rc files ---------------------------*/
int load_stuff(void)
{
/*
* Trawl the UUPC files to get the stuff we need - return TRUE
* if completed ok
*/
int res = 0;
int i;
char buf[256];
char *fn, *p, *v;
FILE *tmp;
/* news base directory */
if ((fn = getenv("UUPCNEWS")) == NULL) {
fprintf(stderr, "UUPCNEWS environment variable undefined");
exit(1);
}
/* give it a trailing \ */
strcpy(my_stuff.news_dir, fn);
if (my_stuff.news_dir[ strlen(my_stuff.news_dir)-1 ] != '\\')
strcat(my_stuff.news_dir, "\\");
/* set other defaults */
strcpy(my_stuff.replyuser, "-none-");
strcpy(my_stuff.uncompress, "compress -d %s");
my_stuff.home[0] = '\0';
my_stuff.signature[0] = '\0';
my_stuff.my_organisation[0] = '\0';
my_stuff.alias_file[0] = '\0';
strcpy(my_stuff.extract_file, "extract.nws");
strcpy(my_stuff.hotpipe, "metamail %s");
if ((v = getenv("EDITOR")) == NULL)
strcpy(my_stuff.editor, "edit %s");
else
strcat(strcpy(my_stuff.editor, v), " %s");
/* get the temporary directory string from the environment in case
it isn't in the configuration file */
if (((v = getenv("TEMP")) != NULL) ||
((v = getenv("TMP")) != NULL))
strcpy(my_stuff.temp_str, v);
else
my_stuff.temp_str[0] = '\0';
strcat(strcpy(my_stuff.temp_name, my_stuff.temp_str), "$unbatch");
/* read the system file first, then the user's personal file */
for (i = 0; i < 2; i++) {
/* choose the file to open */
if (i == 0) {
fn = getenv("SNEWSRC");
if (fn == NULL) {
fn = getenv("UUPCUSRRC");
if (fn == NULL) {
fprintf(stderr, "Enviroment variable SNEWSRC not defined\n");
}
}
}
else {
fn = getenv("UUPCSYSRC");
if (fn == NULL) {
fprintf(stderr, "Enviroment variable UUPCSYSRC not defined\n");
}
}
if ((tmp = fopen(fn, "rt")) != NULL) {
/* read a line from the configuration file */
while (fgets(buf, 255, tmp)) {
if (((p = strtok(buf, " =\r\n")) != NULL) && (*p != '#')) {
v = strtok(NULL, " =\r\n");
if (stricmp(p, "mailserv") == 0) {
strcpy(my_stuff.mail_server, v);
res++;
}
if (strnicmp(p, "color", 5) == 0) {
set_colors(p+5, v);
}
if (stricmp(p, "nodename") == 0) {
strcpy(my_stuff.my_site, v);
res++;
}
if (stricmp(p, "newsdir") == 0) {
strcpy(my_stuff.incoming_dir, v);
if ((my_stuff.incoming_dir[strlen(my_stuff.incoming_dir)-1] != '/') &&
(my_stuff.incoming_dir[strlen(my_stuff.incoming_dir)-1] != '\\'))
strcat(my_stuff.incoming_dir, "/");
expand_filename(my_stuff.incoming_dir);
res++;
}
if (stricmp(p, "domain") == 0) {
strcpy(my_stuff.my_domain, v);
res++;
}
if (stricmp(p, "tempdir") == 0) {
strcpy(my_stuff.temp_str, v);
/* temp_str must end with \ and can't have any / because DOS doesn't like
those for redirection in a system() line
First do a very ugly kludge to see if we're operating on a system that
uses / instead of \
(note to self: don't be so lazy and look up the switchar system call! */
if (getenv("COMSPEC")[2] != '/') {
while (strchr(my_stuff.temp_str, '/'))
*strchr(my_stuff.temp_str, '/') = '\\';
if (my_stuff.temp_str[strlen(my_stuff.temp_str)-1] != '\\')
strcat(my_stuff.temp_str, "\\");
}
expand_filename(my_stuff.temp_str);
/* temporary unbatch file name -- can't have extension */
strcpy(my_stuff.temp_name, my_stuff.temp_str);
strcat(my_stuff.temp_name, "$unbatch");
}
if (stricmp(p, "mailbox") == 0) {
strcpy(my_stuff.user, v);
res++;
}
if (stricmp(p, "Signature") == 0) {
strcpy(my_stuff.signature, v);
expand_filename(my_stuff.signature);
}
if (stricmp(p, "name") == 0) {
strcpy(my_stuff.my_name, v);
v = strtok(NULL, " =\r\n");
while (v != NULL) {
strcat(my_stuff.my_name, " ");
strcat(my_stuff.my_name, v);
v = strtok(NULL, " =\r\n");
}
res++;
}
if (stricmp(p, "Organization") == 0) {
strcpy(my_stuff.my_organisation, v);
v = strtok(NULL, " =\r\n");
while (v != NULL) {
strcat(my_stuff.my_organisation, " ");
strcat(my_stuff.my_organisation, v);
v = strtok(NULL, " =\r\n");
}
}
if (stricmp(p, "Replyto") == 0) {
strcpy(my_stuff.replyuser, v);
v = strtok(NULL, " =\r\n");
while (v != NULL) {
strcat(my_stuff.replyuser, " ");
strcat(my_stuff.replyuser, v);
v = strtok(NULL, " =\r\n");
}
}
if (stricmp(p, "Editor") == 0) {
strcpy(my_stuff.editor, v);
v = strtok(NULL, " =\r\n");
while (v != NULL) {
strcat(my_stuff.editor, " ");
strcat(my_stuff.editor, v);
v = strtok(NULL, " =\r\n");
}
expand_filename(my_stuff.editor);
}
if (stricmp(p, "Uncompress") == 0) {
strcpy(my_stuff.uncompress, v);
v = strtok(NULL, " =\r\n");
while (v != NULL) {
strcat(my_stuff.uncompress, " ");
strcat(my_stuff.uncompress, v);
v = strtok(NULL, " =\r\n");
}
expand_filename(my_stuff.uncompress);
}
if (stricmp(p, "HotPipe") == 0) {
strcpy(my_stuff.hotpipe, v);
v = strtok(NULL, " =\r\n");
while (v != NULL) {
strcat(my_stuff.hotpipe, " ");
strcat(my_stuff.hotpipe, v);
v = strtok(NULL, " =\r\n");
}
expand_filename(my_stuff.hotpipe);
}
if (stricmp(p, "Home") == 0) {
strcpy(my_stuff.home, v);
if (my_stuff.home[ strlen(my_stuff.home)-1 ] != '\\')
strcat(my_stuff.home, "/");
res++;
}
if (stricmp(p, "Aliases") == 0) {
strcpy(my_stuff.alias_file, v);
expand_filename(my_stuff.alias_file);
}
if (stricmp(p, "Extract") == 0) {
strcpy(my_stuff.extract_file, v);
expand_filename(my_stuff.extract_file);
}
} /* if */
} /* while */
fclose (tmp);
}
else {
fprintf(stderr, "Cannot open %s\n", fn);
}
}
return(res >= 7); /* see if all mandatory items have been specified */
}
/*--------------------------- unpack the batch ------------------------*/
FILE *open_out_file(char *ng)
{
/*
* This routine creates a filename from the newsgroup name.
* The active file counter are updated.
*/
ACTIVE *gp;
char *fn;
FILE *tmp;
gp = find_news_group(ng);
fn = make_news_group_name(gp->group);
(gp->hi_num)++;
update_active_entry(gp);
if ((tmp = flockopen(fn, "r+b")) == NULL) {
fprintf(stderr,"active: cannot open text file %s\n", fn);
exit(1);
}
fseek(tmp, 0, SEEK_END);
return(tmp);
}
/*--------------------------- unpack the batch ------------------------*/
FILE *open_index_file(char *ng)
{
/*
* This routine open the index file for the newsgroup
*/
ACTIVE *gp;
char fnx[256], *fn;
FILE *tmp;
/* printf("news: ng found = %s\n", ng); */
gp = find_news_group(ng);
fn = make_news_group_name(gp->group);
sprintf(fnx, "%s.IDX", fn);
if((tmp = flockopen(fnx, "r+b")) == NULL) {
fprintf(stderr, "active: cannot open index file %s\n", fn);
exit(1);
}
fseek(tmp, 0, SEEK_END);
return(tmp);
}
/*------------------------- post sequence number ----------------------------*/
int post_sequence(void)
{
/*
* Get the sequence number from the seq file if it exists - if
* not create it
*/
FILE *seq_file;
char fn[256];
int seq;
strcpy(fn, my_stuff.news_dir);
strcat(fn, "nseq");
if ((seq_file = flockopen(fn, "r+t")) != NULL) {
fscanf(seq_file, "%d", &seq);
seq++;
rewind(seq_file);
} else {
seq = 0;
seq_file = flockopen(fn, "wt");
}
fprintf(seq_file, "%d", seq);
fclose(seq_file);
return(seq);
}
/*-------------------------------- safeish malloc --------------------------*/
void *xmalloc(size_t size)
{
void *p;
if ((p = malloc(size)) == NULL) {
gotoxy(1,25);
fprintf(stderr, "\n\nSORRY - NO MEMORY LEFT \n");
exit(1);
}
return(p);
}
/*------------------------ ctrl-break signal handler -----------------------*/
void cdecl sig_break()
{
signal(SIGINT, sig_break); /* reactive signal */
++break_hit; /* indicate that control-break was hit */
}
/*------------------------- expand ~/ in file name -------------------------*/
char *expand_filename(char *fn)
{
/* if file name starts with ~/ change to user's home directory */
if ((fn[0] == '~') && ((fn[1] == '/') || (fn[1] == '\\')) && fn[2]) {
memmove(fn+strlen(my_stuff.home), fn+2, strlen(fn+2) + 1);
memmove(fn, my_stuff.home, strlen(my_stuff.home));
}
return fn;
}