BSD 4_3 release
[unix-history] / usr / contrib / nntp / server / misc.c
#ifndef lint
static char *sccsid = "@(#)misc.c 1.4 (Berkeley) 3/8/86";
#endif
#include "common.h"
/*
* open_valid_art -- determine if a given article name is valid;
* if it is, return a file pointer to the open article,
* along with a unique id of the article.
*
* Parameters: "artname" is a string containing the
* name of the article.
* "id" is space for us to put the article
* id in.
*
* Returns: File pointer to the open article if the
* article is valid; NULL otherwise
*
* Side effects: None.
*/
FILE *
open_valid_art(artname, id)
char *artname;
char *id;
{
static int crnt_art_num;
static char crnt_art_id[MAX_STRLEN];
int fd;
struct stat statbuf;
if (art_fp != NULL) {
if (crnt_art_num == atoi(artname)) {
if (fseek(art_fp, (long) 0, 0) < 0)
close_crnt();
else {
(void) strcpy(id, crnt_art_id);
return(art_fp);
}
} else
close_crnt();
}
art_fp = fopen(artname, "r");
if (art_fp == NULL)
return(NULL);
fd = fileno(art_fp);
if (fstat(fd, (struct stat *) &statbuf) < 0) {
close_crnt();
return(NULL);
}
if ((statbuf.st_mode & S_IFREG) != S_IFREG) {
close_crnt();
return(NULL);
}
get_id(art_fp, id);
(void) strcpy(crnt_art_id, id);
crnt_art_num = atoi(artname);
return(art_fp);
}
/*
* openartbyid -- open an article by message-id.
*
* Parameters: "msg_id" is the message ID of the
* article, enclosed in <>'s.
*
* Returns: A file pointer to the open article,
* or NULL if the article doesn't exist.
*
* Side effects: Displays article, opens dbm database
* (only once, keeps it open after that).
* Converts "msg_id" to lower case.
*/
FILE *
openartbyid(msg_id)
char *msg_id;
{
char line[MAX_STRLEN], path[MAX_STRLEN];
char *tmp;
register char *cp;
FILE *art_fp;
#ifdef DBM
static int dbopen;
datum fetch();
#else
static DBM *db; /* History file, dbm version */
#endif
static FILE *hfp; /* history file, text version */
datum key, content;
#ifdef DBM
if (!dbopen) {
if (dbminit(HISTORY_FILE) < 0) {
syslog(LOG_ERR, "nntpd: openartbyid: dbminit %s: %m\n",
HISTORY_FILE);
return (NULL);
} else
dbopen = 1;
}
#else
if (db == NULL) {
db = dbm_open(HISTORY_FILE, O_RDONLY, 0);
if (db == NULL) {
syslog(LOG_ERR, "nntpd: openartbyid: dbm_open %s: %m\n",
HISTORY_FILE);
return (NULL);
}
}
#endif
for (cp = msg_id; *cp != '\0'; ++cp)
if (isupper(*cp))
*cp = tolower(*cp);
key.dptr = msg_id;
key.dsize = strlen(msg_id) + 1;
#ifdef DBM
content = fetch(key);
#else
content = dbm_fetch(db, key);
#endif
if (content.dptr == NULL)
return (NULL);
if (hfp == NULL) {
hfp = fopen(HISTORY_FILE, "r");
if (hfp == NULL) {
syslog(LOG_ERR, "nntpd: message: fopen %s: %m\n",
HISTORY_FILE);
return (NULL);
}
}
if (fseek(hfp, (long) *(int *)content.dptr, 0) < 0) {
syslog(LOG_ERR, "nntpd: message: fseek: %m\n");
return (NULL);
}
(void) fgets(line, sizeof(line), hfp);
if ((cp = index(line, '\n')) != NULL)
*cp = '\0';
cp = index(line, '\t');
if (cp != NULL)
cp = index(cp+1, '\t');
if (cp == NULL) {
syslog(LOG_ERR,
"nntpd: message: malformed line in history file (%d bytes)\n",
(int) *(int *)content.dptr);
return (NULL);
}
tmp = cp+1;
if ((cp = index(tmp, ' ')) != NULL)
*cp = '\0';
while ((cp = index(tmp, '.')) != NULL)
*cp = '/';
(void) strcpy(path, homedir);
(void) strcat(path, "/");
(void) strcat(path, tmp);
art_fp = fopen(path, "r");
return (art_fp);
}
/*
* spew -- spew out the contents of a file to stdout, doing
* the necessary cr-lf additions at the end. Finish with
* a "." on a line by itself, and an fflush(stdout).
*
* Parameters: "how" tells what part of the file we
* want spewed:
* ARTICLE The entire thing.
* HEAD Just the first part.
* BODY Just the second part.
* "fp" is the open file to spew from.
*
* Returns: Nothing.
*
* Side effects: Changes current position in file.
*/
spew(fp, how)
FILE *fp;
int how;
{
char line[512];
register char *cp;
#ifdef LOG
++arts_acsd;
#endif
if (how == STAT) {
(void) fflush(stdout);
return;
}
while (fgets(line, sizeof(line)-6, fp) != NULL && *line != '\n') {
if (how == BODY) /* We need to skip this anyway */
continue;
cp = index(line, '\n');
if (cp != NULL)
*cp = '\0';
if (*line == '.')
putchar('.');
printf("%s\r\n", line);
if (cp == NULL) {
for (;;) {
if ((fgets(line, sizeof(line)-6, fp) == NULL)
|| (index(line, '\n') != NULL))
break;
}
}
}
if (how == HEAD) {
putchar('.');
putchar('\r');
putchar('\n');
(void) fflush(stdout);
return;
} else if (how == ARTICLE) {
putchar('\r');
putchar('\n');
}
while (fgets(line, sizeof(line)-6, fp) != NULL) {
cp = index(line, '\n');
if (cp != NULL)
*cp = '\0';
if (*line == '.')
putchar('.');
printf("%s\r\n", line);
if (cp == NULL) {
for (;;) {
if ((fgets(line, sizeof(line)-6, fp) == NULL)
|| (index(line, '\n') != NULL))
break;
}
}
}
putchar('.');
putchar('\r');
putchar('\n');
(void) fflush(stdout);
}
/*
* get_id -- get the message id of the current article.
*
* Parameters: "art_fp" is a pointer to the open file.
* "id" is space for the message ID.
*
* Returns: Nothing.
*
* Side effects: Seeks and rewinds on "art_fp".
* Changes space pointed to by "id".
*/
get_id(art_fp, id)
register FILE *art_fp;
char *id;
{
char line[MAX_STRLEN];
register char *cp;
while (fgets(line, sizeof(line), art_fp) != NULL) {
if ((cp = index(line, '\n')) != NULL)
*cp = '\0';
if (*line == '\0')
break;
if ((cp = index(line, ' ')) != NULL) {
*cp = '\0';
if (streql(line, "Message-ID:")) {
(void) strcpy(id, cp + 1);
(void) rewind(art_fp);
return;
}
}
}
(void) strcpy(id, "<0>");
(void) rewind(art_fp);
}
/*
* close_crnt -- close the current article file pointer, if it's
* open.
*
* Parameters: None.
*
* Returns: Nothing.
*
* Side effects: Closes "art_fp" if it's open; sets "art_fp" to NULL.
*/
close_crnt()
{
if (art_fp != NULL)
(void) fclose(art_fp);
art_fp = NULL;
}
/*
* findart -- find an article number in the article array.
*
* Parameters: "artname" is a string containing
* the name of the article.
*
* Returns: An index into "art_array",
* or -1 if "artname" isn't in "art_array".
*
* Side effects: None.
*
* Improvement: Replace this linear search with a binary one.
*/
findart(artname)
char *artname;
{
register int i, artnum;
artnum = atoi(artname);
for (i = 0; i < num_arts; ++i)
if (art_array[i] == artnum)
return(i);
return(-1);
}
/*
* get_distlist -- return a nicely set up array of distribution groups
* along with a count, when given an NNTP-spec distribution list
* in the form <dist1,dist2,...,distn>.
*
* Parameters: "array" is storage for our array,
* set to point at some static data.
* "list" is the NNTP distribution list.
*
* Returns: Number of distributions found.
* -1 on error.
*
* Side effects: Changes static data area.
*/
get_distlist(array, list)
char ***array;
char *list;
{
char *cp;
int distcount;
static char **dist_list = (char **) NULL;
if (list[0] != '<')
return (-1);
cp = index(list + 1, '>');
if (cp != NULL)
*cp = '\0';
else
return (-1);
for (cp = list + 1; *cp != '\0'; ++cp)
if (*cp == ',')
*cp = ' ';
distcount = parsit(list + 1, &dist_list);
*array = dist_list;
return (distcount);
}
/*
* spawn -- create a child process with the input from the client
* as stdin.
*
* Parameters: "path" is the path of the program to invoke.
* "name" is the name to call the program.
* "flag" is a single flag to be passed to the program.
* "cont_code" is the response code to transmit
* on successful startup.
* "err_code" is the response code to transmit when
* something goes wrong.
*
* Returns: -1 on non-zero return from child,
* 0 on error before fork/exec,
* 1 otherwise.
*
* Side effects: Creates and removes temporary file;
* accepts input from client; forks and execs.
*/
spawn(path, name, flag, cont_code, err_code)
char *path;
char *name;
char *flag;
int cont_code;
int err_code;
{
char tempfile[256], line[MAX_STRLEN];
register char *cp;
int i, nds, fd;
int exit_status;
union wait status;
register FILE *fp;
(void) strcpy(tempfile, "/tmp/rpostXXXXXX");
(void) mktemp(tempfile);
fp = fopen(tempfile, "w");
if (fp == NULL) {
printf("%d Cannot create temporary file.\r\n", err_code);
(void) fflush(stdout);
return (0);
} else {
printf("%d Enter news, period on a line by itself to end.\r\n",
cont_code);
(void) fflush(stdout);
}
while (fgets(line, sizeof(line), stdin) != NULL) {
if ((cp = index(line, '\r')) != NULL)
*cp = '\0';
else if ((cp = index(line, '\n')) != NULL)
*cp = '\0';
if (strcmp(line, ".") == 0)
break;
if (line[0] == '.')
fprintf(fp, "%s\n", line+1);
else
fprintf(fp, "%s\n", line);
}
(void) fclose(fp);
/*
* Ok, now we have the article in "tempfile". We
* should be able to fork off, close fd's 0 to 31 (or
* whatever), open "tempfile" for input, thus making
* it stdin, and then execl the inews. We think.
*/
if (fork() == 0) { /* We're in child */
#ifdef POSTER
(void) setuid(uid_poster);
(void) setgid(gid_poster);
#endif
nds = getdtablesize();
for (i = 0; i < nds; ++i)
(void) close(i);
fd = open(tempfile, O_RDONLY);
if (fd != 0) {
(void) dup2(fd, 0);
(void) close(fd);
}
fd = open("/", O_RDONLY);
if (fd != 1) {
(void) dup2(fd, 1);
(void) close(fd);
}
(void) dup2(1, 2);
execl(path, name, flag, (char *) NULL);
exit(-1); /* Error */
} else {
while (wait(&status) > 0)
exit_status = status.w_T.w_Retcode;
(void) unlink(tempfile);
(void) fflush(stdout);
return (exit_status ? -1 : 1);
}
}
/*
* streql -- determine if two strings are equal, ignoring case.
*
* Parameters: "a" and "b" are the pointers
* to characters to be compared.
*
* Returns: 1 if the strings are equal, 0 otherwise.
*
* Side effects: None.
*/
streql(a, b)
register char *a, *b;
{
char lower();
while (lower(*a) == lower(*b)) {
if (*a == '\0')
return (1);
a++;
b++;
}
return (0);
}
/*
* lower -- convert a character to lower case, if it's
* upper case.
*
* Parameters: "c" is the character to be
* converted.
*
* Returns: "c" if the character is not
* upper case, otherwise the lower
* case eqivalent of "c".
*
* Side effects: None.
*/
char lower(c)
register char c;
{
if (isascii(c) && isupper(c))
c = c - 'A' + 'a';
return(c);
}