home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Pier Shareware 6
/
The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso
/
024
/
psi110g.zip
/
NNTPSERV.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-26
|
105KB
|
3,882 lines
/*
*
* NNTP Server/Client - See RFC977
* Jeffrey R. Comstock. - NR0D - Bloomington, Minnesota USA
* Copyright 1990 Jeffrey R. Comstock, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
*
* DB3FL 9107xx: heavily rewritten and bug fixing in file-handling
* ported to NOS by PE1NMB - 920120
*
* DB3FL: ihave, read & lzw ported to NOS by YC1DAV 920804
*
* Mods by PA0GRI
*
* OH2BNS 9311xx: Fixed LIST, STAT, HEAD and BODY. Implemented POST.
* Added 'nntp create'. Small fixes here and there...
*
* OH2BNS 9401xx: Rewrote STAT, HEAD, BODY, ARTICLE. Implemented
* XHDR, XOVER, 'nntp access'. Rewrote garbled().
*/
#include <time.h>
#include <stdarg.h>
#include <ctype.h>
#include <setjmp.h>
#ifdef MSDOS
#include <dos.h>
#include <dir.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef LINUX
#include <fcntl.h>
#endif
#ifdef MSDOS
#include <io.h>
#endif
#include "global.h"
#ifdef NNTPS
#include "domain.h"
#include "mbuf.h"
#include "cmdparse.h"
#include "socket.h"
#include "iface.h"
#include "proc.h"
#include "smtp.h"
#include "commands.h"
#include "dirutil.h"
#include "ftp.h"
#include "netuser.h"
#include "nntp.h"
#include "session.h"
#include "files.h"
#include "smtp.h"
#include "bm.h"
#ifdef LESS_WHINING
#include "pc.h"
#include "nr4.h"
#include "netrom.h"
#include "udp.h"
#include "tcp.h"
#include "ip.h"
#include "usock.h"
#endif
#ifdef LZW
#include "lzw.h"
#endif
FILE *open_file __ARGS((char *name,char *mode,int s,int t));
FILE *temp_file __ARGS((int s,int t)); /* NMB */
static int near make_dir __ARGS((char *path,int s));
static int check_file __ARGS((char *path));
static int make_path __ARGS((char *group));
static int check_blank __ARGS((char *bp));
static int dup_f __ARGS((FILE *in,FILE *out,struct nntpsv *mp));
static int update_list __ARGS((struct nntpsv *a));
static int get_path2 __ARGS((struct article *art));
static int dofwd __ARGS((struct nntpsv *mp,FILE *f,FILE *history));
static int getreply __ARGS((struct nntpsv *cb));
static int newnews __ARGS((char *string,struct nntpsv *mp,FILE *f));
static int recv_file __ARGS((FILE *fp,int s));
static int check_article __ARGS((char *id));
static int xfer_article2 __ARGS((FILE *f,struct nntpsv *mp));
static int retr_by_mid __ARGS((char *mid,struct nntpsv *mp));
static int retr_by_num __ARGS((char *buf,struct nntpsv *mp));
static int doarticlecmd __ARGS((char *buf,struct nntpsv *mp));
static int doheadcmd __ARGS((char *buf,struct nntpsv *mp));
static int dobodycmd __ARGS((char *buf,struct nntpsv *mp));
static int dostatcmd __ARGS((char *buf,struct nntpsv *mp));
static int doxhdrcmd __ARGS((char *buf,struct nntpsv *mp));
static int doxovercmd __ARGS((char *buf,struct nntpsv *mp));
static int restreql __ARGS((register char *w,register char *s));
static int check_one __ARGS((register char *str));
static int32 make_nntime __ARGS((struct date *d,struct time *t,char *str));
static int ngmatcha __ARGS((int (*func)(char *,char *),int dflt,struct g_list *ngspec,struct g_list *matchlist));
static int get_path __ARGS((char *group,struct nntpsv *mp));
static int get_pointer __ARGS((char *group,struct nntpsv *mp));
static FILE *open_message __ARGS((struct nntpsv *mp,FILE *f));
static int get_id __ARGS((char *bp,struct nntpsv *mp));
static int garbled __ARGS((FILE *inf,FILE *outf));
static int donewnews __ARGS((char *string,struct nntpsv *mp));
static int dogroup __ARGS((struct nntpsv *mp,char *buf));
static int check_grp __ARGS((struct nntpsv *mp));
static int get_next __ARGS((struct nntpsv *mp));
static int get_last __ARGS((struct nntpsv *mp));
void poll __ARGS((void *p));
static int get_article2 __ARGS((struct nntpsv *mp,char *id));
static int post_article __ARGS((struct nntpsv *mp));
static int donnprofile __ARGS((int argc,char *argv[],void *p));
static int chk_access __ARGS((int s));
static int donnfirstpoll __ARGS((int argc,char *argv[],void *p));
static void make_time_string(char *string,time_t *timep);
/***************************************************************************/
#undef CONTROL /* reverse NNTP function (not implemented yet) */
#define LINE 80
#ifdef LZW
int LzwActive = 1;
#endif
static int16 Nntpquiet = 0;
static int16 NnIhave = 0;
int Nntpaccess = 0;
static int Nntpfirstpoll = 5;
int Filecheck = 0; /* flag if file system has been checked */
long GMT_offset; /* our offset from GMT, in seconds. Positive if W Longitude. */
struct post *Post = NULLPOST;
struct Servers *Nntpserver = NULLSERVER;
static char *Host = NULLCHAR;
static char NEol[] = ".\n";
static char replyto[] = "Reply-To: ";
/* RFC1036 required headers */
static char frm[] = "From: ";
static char dte[] = "Date: ";
static char ngrps[] = "Newsgroups: ";
static char subj[] = "Subject: ";
static char msgid[] = "Message-ID: ";
static char pth[] = "Path: ";
/*############################ NNTP COMMANDS #################################*/
/* Command table */
static char *commands[] = {
"article",
#define ARTICLE_CMD 0
"body",
#define BODY_CMD 1
"debug",
#define DEBUG_CMD 2
"group",
#define GROUP_CMD 3
"head",
#define HEAD_CMD 4
"help",
#define HELP_CMD 5
"ihave",
#define IHAVE_CMD 6
"last",
#define LAST_CMD 7
"list",
#define LIST_CMD 8
"newnews",
#define NEWNEWS_CMD 9
"next",
#define NEXT_CMD 10
"post",
#define POST_CMD 11
"quit",
#define QUIT_CMD 12
"slave",
#define SLAVE_CMD 13
"stat",
#define STAT_CMD 14
"xhdr",
#define XHDR_CMD 15
"xinfo",
#define XINFO_CMD 16
"xlzw",
#define XLZW_CMD 17
"xover",
#define XOVER_CMD 18
"newgroups",
#define NEWGROUPS_CMD 19
NULLCHAR
};
static char artmsg[] = " Article retrieved - ";
/*static char info[] = "100 %s Info:\n";*/
static char xinfo[] = "100 No info available\n";
static char debug[] = "100 Debug %s\n";
static char nnversion[] = "20%s %s NNTP version %s ready at %s %s\n";
static char slave[] = "202 Slave %s\n";
static char closing[] = "205 Closing\n";
static char listarticle[]= "211 %u %u %u%s\n";
static char listgroups[]= "215 List of newsgroups follows\n";
static char newgroups[] = "231 List of new newsgroups follows\n";
static char retrieve[] = "220 %u%s%shead and body follow\n";
static char head[] = "221 %u%s%sHead\n";
static char xheader1[] = "221 %s fields follow\n";
static char xheader2[] = "221 %u %s header of article %s\n";
static char body[] = "222 %u%s%sBody\n";
static char statistics[]= "223 %u%s%sStatistics\n";
static char sepcmd[] = "223 %u %s%srequest text separately\n";
static char xover[] = "224 data follows\n";
static char newnews_t[] = "230 New news by message id follows\n";
static char transok[] = "235 Thanks\n";
static char postok[] = "240 Article posted ok\n";
static char sendart[] = "335 Send article, end with .\n";
static char sendpost[] = "340 Send article to be posted, end with .\n";
static char nogroup[] = "411 No such newsgroup\n";
static char noselect[] = "412 No newsgroup selected\n";
static char nonext[] = "421 No next article\n";
static char noprev[] = "422 No previous article\n";
static char noart[] = "430 No such article\n";
static char notwanted[] = "435 Article not wanted - do not send it\n";
static char transnotok[]= "437 Article rejected - header garbled - do not try again\n";
static char notallowed[]= "440 Posting not allowed\n";
static char postfailed[]= "441 Posting failed";
static char notrecognd[]= "500 Command not recognized\n";
static char badsyntax[] = "501 Syntax error\n";
static char noaccess[] = "502 I'm not allowed to talk to you\n";
static char error[] = "503 Command not performed\n";
/*static char nospace[] = "503 Not enough disk space left\n"; */
static char lowmem[] = "503 System overloaded\n";
static char fatal[] = "503 Fatal error FILE %s\n";
static char quitcmd[] = "QUIT\n";
static void near
rip2(register char *s)
{
register char *cp;
if((cp = strpbrk(s,"\r\n")) != NULLCHAR)
*cp = '\0';
}
/* main directory-creating routine
* handles special chars in pathname - especially for MSDOS
* returncode: -1 error; 0 success
*/
static int near
make_dir(path,s)
char *path;
int s;
{
#ifdef MSDOS
register char *cp;
#endif
if(path == NULLCHAR)
return -1;
#ifdef MSDOS
while((cp = strchr(path,'\\')) != NULLCHAR)
*cp = '/';
#endif
if (access(path,0)) {
#ifdef UNIX
if (mkdir(path,0755)) { /* 0755 is drwxr-xr-x */
#else
if (mkdir(path)) {
#endif
tprintf("Can't create %s: %s\n",path,sys_errlist[errno]);
if(s)
usprintf(s,fatal,path);
return -1;
}
}
return 0;
}
/* main message-opening routine
* returncode: NULLFILE if error; filepointer success */
static FILE *
open_message(mp,f)
struct nntpsv *mp;
FILE *f;
{
char line[LineLen];
/* mp already checked */
if(f != NULLFILE)
fclose(f);
sprintf(line,"%s/%u",mp->path,mp->pointer);
if ((f = open_file(line,READ_TEXT,0,0)) == NULLFILE)
usputs(mp->s,"430 Error opening message - no such article.\n");
return f;
}
/* file-receiving routine
* returncode: -1 if error or 'recvline' faults; 0 success; 1 if blank line */
static int
recv_file(fp,s)
FILE *fp;
int s;
{
char line[LineLen];
int ret,check = 0;
for (;;) {
if (recvline(s,line,LineLen) == -1)
return -1;
rip2(line);
if (strcmp(line,".") == 0)
return 0;
if(!check) { /* only enabled on first line! */
check = 1;
if (*line == '\0') /* check for blank line */
return 1;
}
fprintf(fp,"%s\n",line);
}
}
/* checks incoming article-id against existing articles
* returncode: -1 if error; 1 if article exists; 0 no article found */
/* Now also makes a crude format check - OH2BNS */
static int
check_article(id)
char *id;
{
char *p, *p1, line[LineLen];
FILE *f;
if(id == NULLCHAR || (p = strchr(id,'<')) == NULLCHAR
|| (f = open_file(History,READ_TEXT,0,1)) == NULLFILE)
return -1;
p1 = p;
while (*p1 != '\0' && *p1 != '>' && !isspace(*p1))
p1++;
if (*p1 != '>' || *++p1 != '\0')
return -1;
for(;;) {
if (fgets(line,LineLen,f) == NULL) {
fclose(f);
return 0;
}
if (!strncmp(line,p,strlen(p))) {
fclose(f);
return 1;
}
}
pwait(NULL); /* let other processes run */
}
/* checks for not valid chars in a line
* returncode: 0 if valid; 1 if invalid */
static int
check_blank(bp)
char *bp;
{
if (strpbrk(bp,"!@#$%^&*()_+=<>,./?~`[]{}\\|0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") == NULL)
return 1;
return 0;
}
/* main file-checking routine
* returncode: -1 if error; 0 success */
static int
check_file(path)
char *path;
{
if(path == NULLCHAR)
return -1;
if(access(path,0))
#ifdef UNIX
return close(creat(path,0644)); /* 0644 is -rw-r--r-- */
#else
return close(creat(path,S_IWRITE));
#endif
return 0;
}
/* checks if two spaces exists in given string
* returncode: -1 if error; 1 success */
static int
check_one(str)
register char *str;
{
register char *cp;
if(str == NULLCHAR || (cp = strchr(str,' ')) == NULLCHAR)
return -1;
cp++;
if (strchr(cp,' ') == NULLCHAR)
return -1;
return 1;
}
/* obtain offset from GMT, in seconds. Positive if W Longitude. -- N5KNX */
static long
get_GMT_offset(void)
{
struct tm *ltm;
time_t t;
int i;
time(&t);
ltm = gmtime(&t);
i = ltm->tm_hour*60 + ltm->tm_min;
ltm = localtime(&t);
i -= (ltm->tm_hour*60 + ltm->tm_min);
return (long)i*60L; /* in seconds */
}
/* checks the file-system used for NNTP
* returncode: -1 if error; 0 success - and "Filecheck" is set to 1 */
static int
check_system(void)
{
FILE *f;
char line[LineLen];
int error = 0;
if (Post == NULLPOST)
donnprofile(10,NULL,NULL);
if(Filecheck)
return 0;
error = make_dir(Forward,0);
error |= check_file(Pointer);
error |= check_file(History);
error |= check_file(Active);
error |= check_file(Poll);
error |= check_file(Naccess);
if(error)
goto quit;
sprintf(line,"%s/fwd.seq",Newsdir);
if (access(line,0)) {
if((f = open_file(line,"w+",0,1)) == NULLFILE) {
goto quit;
}
fputs("1\n",f);
fclose(f);
}
sprintf(line,"%s/sequence.seq",Mailqdir);
if (access(line,0)) {
if((f = open_file(line,"w+",0,1)) == NULLFILE) {
goto quit;
}
fputs("1\n",f);
fclose(f);
}
GMT_offset = get_GMT_offset();
Filecheck = 1;
return 0;
quit:
Filecheck = 0;
tputs("Error in NNTP file system\n");
return -1;
}
/* handles the response code of an incoming msg
* returncode: -1 error; 0 no code; value of response code on success */
static int
getreply(cb)
struct nntpsv *cb;
{
int response;
while(recvline(cb->s,cb->buf,LineLen) != -1) {
/* skip informative messages and blank lines */
if(cb->buf[0] == '\0' || cb->buf[0] == '1')
continue;
sscanf(cb->buf,"%d",&response);
return (response < 500) ? response : -1;
}
return -1;
}
/* returncode: -1 error; 1 success; 0 no entry */
static int
get_path(group,mp)
char *group;
struct nntpsv *mp;
{
FILE *f;
char line[LineLen], *cp;
if(group == NULLCHAR || mp == NULLNNTPSV
|| (f = open_file(Pointer,READ_TEXT,mp->s,0)) == NULLFILE)
return -1;
group++;
for (;;) {
if (fgets(line,LineLen,f) == NULL)
break;
if (strcspn(line," ") != strlen(group))
continue;
if (strnicmp(group,line,strlen(group)) == 0) {
cp = (strchr(line,' ')) + 1;
if (mp->path != NULLCHAR)
free(mp->path);
mp->path = strdup(cp);
rip2(mp->path);
fclose(f);
return 1;
}
}
fclose(f);
return 0;
}
/* checkes if path to given article exists
* returncode: -1 error; 1 success; 0 no path */
static int
get_path2(art)
struct article *art;
{
FILE *f;
char line[LineLen], *p;
if(art->group == NULLCHAR
|| (f = open_file(Pointer,READ_TEXT,0,1)) == NULLFILE)
return -1;
p = art->group;
art->path = NULLCHAR;
for (;;) {
if (fgets(line,LineLen,f) == NULL)
break;
if (strcspn(line," ") != strlen(p))
continue;
if (strnicmp(p,line,strlen(p)) == 0) {
p = (strchr(line,' ')) + 1;
if(art->path != NULLCHAR)
free(art->path);
art->path = strdup(p);
rip2(art->path);
fclose(f);
return 1;
}
}
fclose(f);
return 0;
}
/* returncode: -1 if error; 1 success; 0 no pointer */
static int
get_pointer(group,mp)
char *group;
struct nntpsv *mp;
{
FILE *f;
char line[LineLen], *p;
if(group == NULLCHAR || mp == NULLNNTPSV
|| (f = open_file(Active,READ_TEXT,mp->s,0)) == NULLFILE)
return -1;
group++;
for (;;) {
if (fgets(line,LineLen,f) == NULL)
break;
if (strcspn(line," ") != strlen(group))
continue;
if (strnicmp(group,line,strlen(group))==0) {
p = strchr(line,' ');
mp->last = (unsigned)atoi(p);
p++;
mp->first = (unsigned)atoi(strchr(p,' '));
mp->pointer = (mp->first > mp->last ) ? 0 : mp->first;
fclose(f);
return 1;
}
}
fclose(f);
return 0;
}
/* creating path to a new newsgroup
* handling of "." and "\" in pathnames especially MSDOS */
/* returncode: -1 error; 0 success */
static int
make_path(group)
char *group;
{
FILE *f;
char cp[LineLen], cp1[LineLen], *cp2;
int got_it;
if (group == NULLCHAR
|| (f = open_file(Pointer,APPEND_TEXT,0,1)) == NULLFILE)
return -1;
got_it = 0;
strcpy(cp1,group);
for(;;) {
if((cp2 = strchr(cp1,'.')) != NULLCHAR)
*cp2 = '\0';
else
got_it = 1;
sprintf(cp,"%s/%s",Newsdir,cp1);
if(make_dir(cp,0)) {
fclose(f);
return -1;
}
if(got_it) {
fprintf(f,"%s %s\n",group,cp);
fclose(f);
return 0;
}
*cp2 = '/';
}
}
static int
update_list(a)
struct nntpsv *a;
{
FILE *f, *t;
char *p, *p1, l2[LineLen];
if((f = open_file(Active,READ_TEXT,a->s,0)) == NULLFILE)
return -1;
if ((t = temp_file(0,1)) == NULLFILE) {
fclose(f);
return -1;
}
p1 = a->ap->group;
a->ap->number = 0;
for (;;) {
if (fgets(a->buf,LineLen,f) == NULL)
break;
a->ap->tmpu = strcspn(a->buf," ");
strncpy(l2,a->buf,a->ap->tmpu);
l2[a->ap->tmpu] = '\0';
p = strrchr(a->buf,' ') + 1; /* the char after the last space */
if (*p == 'n') { /* posting to this group not allowed */
fputs(a->buf,t);
continue;
}
if (strcmp(p1,l2) == 0) {
p = strchr(a->buf,' ') + 1;
a->ap->number = (unsigned)atoi(p);
(a->ap->number)++;
p = strchr(p,' ');
fprintf(t,"%s %5.5u%s",p1,a->ap->number,p);
} else
fputs(a->buf,t);
}
fclose(f);
rewind(t);
if ((f = open_file(Active,WRITE_TEXT,a->s,0)) == NULLFILE) {
fclose(t);
return -1;
}
for(;;) {
pwait(NULL);
if (fgets(a->buf,LineLen,t) == NULL)
break;
fputs(a->buf,f);
}
fclose(t);
/* Creating newsgroups by posting is now denied - OH2BNS
*
* if (a->ap->number == 0) {
* make_path(a->ap->group);
* a->ap->number = 1;
* fprintf(f,"%s 00001 00001 y\n",a->ap->group);
* }
*/
fclose(f);
return (a->ap->number);
}
/* returncode: -1 error; 0 success */
static int
dup_f(in,out,mp)
FILE *in;
FILE *out;
struct nntpsv *mp;
/* Path: bug in col 1 of article body bug fixed by G4JEC 901019....*/
{
char *p;
int blank_line_flag = 1;
for(;;) {
pwait(NULL);
if (fgets(mp->buf,LineLen,in) == NULL)
return 0;
if (blank_line_flag)
if (strnicmp(mp->buf,pth,5) == 0) {
p = strchr(mp->buf,' ') + 1;
fprintf(out,"%s%s!%s",pth,Host,p);
continue;
}
/* oh oh - nntpserv is modifying articles....*/
if (strlen(mp->buf) == 1 && mp->buf[0] == '.')
continue;
fputs(mp->buf,out);
/* ! removed. Now dup_f searches the whole header for "Path: ",
* not only the first line - OH2BNS */
if(check_blank(mp->buf))
blank_line_flag = 0;
}
}
/* returncode: < 1 if error; 1 success */
static int
dofwd(mp,f,history)
struct nntpsv *mp;
FILE *f;
FILE *history;
{
FILE *fwd;
if(mp == NULLNNTPSV)
return -1;
sprintf(mp->buf,"%s/fwd.seq",Newsdir);
if ((fwd = open_file(mp->buf,"r+",mp->s,0)) == NULLFILE)
return -1;
fgets(mp->buf,LineLen,fwd);
mp->hold_i = atoi(mp->buf) + 1;
fprintf(history," JUNK/%u",mp->hold_i);
rewind(fwd);
fprintf(fwd,"%u",mp->hold_i);
fclose(fwd);
sprintf(mp->buf,"%s/%u",Forward,mp->hold_i);
if ((fwd = open_file(mp->buf,WRITE_TEXT,mp->s,0)) == NULLFILE)
return -2;
rewind(f);
dup_f(f,fwd,mp);
fclose(fwd);
return 1;
}
#ifdef CONTROL
static int
docontrol(f,mp)
FILE *f;
struct nntpsv *mp;
{
struct head *h;
if(f == NULLFILE || mp == NULLNNTPSV
|| (h = (struct head *)callocw(1,sizeof(struct head))) == NULLHEAD))
return -1;
rewind(f);
h->subject = h->from = h->reply_to = h->id = NULLCHAR;
for(;;) {
pwait(NULL);
if ((fgets(mp->buf,LineLen,f)) == NULL)
break;
if (check_blank(mp->buf))
break;
rip2(mp->buf);
if (strncmp(mp->buf,subj,9) == 0)
h->subject = strdup(mp->buf);
if (strncmp(mp->buf,frm,6) == 0)
h->from = strdup(mp->buf);
if (strnicmp(mp->buf,replyto,10) == 0)
h->reply_to = strdup(mp->buf);
if (strnicmp(mp->buf,msgid,12) == 0)
h->id = strdup(strchr(mp->buf,'<'));
}
if (h->subject != NULLCHAR)
if (strncmp(h->subject,"Subject: sendme ",16) == 0)
dosendme(h);
if (h->subject != NULLCHAR)
free(h->subject);
if (h->from != NULLCHAR)
free(h->from);
if (h->reply_to != NULLCHAR)
free(h->reply_to);
if (h->id != NULLCHAR)
free(h->id);
free((char *)h);
return 0;
}
#endif
static int
xfer_article2(f,mp)
FILE *f;
struct nntpsv *mp;
{
char line[LineLen], *p, *group = NULLCHAR, *p1, *from = NULLCHAR;
FILE *fptr, *history;
struct tm *stm;
int x=0;
#ifdef CONTROL
int control = 0;
#endif
long currtime;
if(f == NULLFILE || mp == NULLNNTPSV)
return -1;
while(mlock(History, NULLCHAR)) {
pause(1000L);
if (++x == 60) {
log(-1, "NNTP: NEWS REJECTED due to history lock");
return -1; /* can't lock, so reject (what else? n5knx) */
}
}
/* one last time check the message-id for duplicates */
if(check_article(mp->id) ||
(history = open_file(History,APPEND_TEXT,mp->s,0)) == NULLFILE) {
rmlock(History, NULLCHAR);
return -1;
}
for (;;) { /* obtain From: and Newsgroups: fields from article */
if (fgets(line,LineLen,f) == NULL)
break;
rip2(line);
if (strnicmp(line,frm,6) == 0) {
p = strchr(line,' ') + 1;
from = strdup(p);
if (group != NULLCHAR) break;
continue;
}
if (strnicmp(line,ngrps,12) == 0) {
p = strchr(line,' ') + 1;
group = strdup(p);
if (from != NULLCHAR) break;
continue;
}
}
time(&currtime);
make_time_string(line,&currtime);
fprintf(history,"%s %s", mp->id, line);
mp->hold_i = 0;
p = group;
if((mp->ap = (struct article *)callocw(1,sizeof(struct article))) == NULLARTICLE)
goto quit;
x = 1;
while (x) {
if ((p1 = strchr(p,',')) != NULLCHAR) {
p1 = line;
while (*p != ',')
*(p1++)=*(p++);
*p1 = '\0';
p++;
mp->ap->group = strdup(line);
} else {
mp->ap->group = strdup(p);
x = 0;
}
update_list(mp);
if (mp->ap->number > 0) {
get_path2(mp->ap);
mp->hold_i = 1;
sprintf(line,"%s/%u",mp->ap->path,mp->ap->number);
rewind(f);
if ((fptr = open_file(line,WRITE_TEXT,mp->s,0)) == NULLFILE) {
fclose(history);
free(mp->ap->group);
goto quit;
}
dup_f(f,fptr,mp);
fclose(fptr);
fprintf(history," %s/%d",mp->ap->group,mp->ap->number);
#ifdef CONTROL
if (strcmp(mp->ap->group,"control") == 0)
control = 1;
#endif
free(mp->ap->path);
}
free(mp->ap->group);
}
if (mp->hold_i == 0) {
dofwd(mp,f,history);
mp->hold_i = 0;
}
fputc('\n',history);
fclose(history);
time(&currtime);
if(Nntpquiet < 2)
tprintf("New mail in newsgroup %s\n from <%s> at %s%s",
(mp->hold_i) ? group : "JUNK",from,ctime(&currtime),
(Nntpquiet < 1) ? "\007" : "");
#ifdef CONTROL
if (control == 1)
docontrol(f,mp);
#endif
quit:
rmlock(History, NULLCHAR);
free(from);
free(group);
free((char *)mp->ap);
return (mp->hold_i);
}
static void
nntppoll(unused,cb1,p)
int unused;
void *cb1;
void *p;
{
char *cp, line[LineLen];
struct sockaddr_in fsocket;
struct nntpsv *cb;
struct tm *stm, *ltm;
FILE *f, *f1, *pf;
long t;
int r, now, ret;
struct Servers *sp = (struct Servers *) cb1;
long currtime;
char open_time[15];
if (!run_timer(&sp->nntpt)) /* if timer had stopped there is an
return; * active session */
if (!Filecheck)
if(check_system())
return;
if(availmem() < Memthresh) {
start_timer(&sp->nntpt);
return;
}
/* check connection window */
time(&currtime);
ltm = localtime(&currtime);
now = ltm->tm_hour * 100 + ltm->tm_min;
if (sp->lowtime < sp->hightime) {
/* doesn't cross midnight */
if (now < sp->lowtime || now >= sp->hightime) {
start_timer(&sp->nntpt);
return;
}
} else {
if (now < sp->lowtime && now >= sp->hightime) {
start_timer(&sp->nntpt);
return;
}
}
if((pf = open_file(Poll,"r+",0,1)) == NULLFILE ||
(cb = (struct nntpsv *)callocw(1,sizeof(struct nntpsv))) == NULLNNTPSV) {
start_timer(&sp->nntpt);
return;
}
stop_timer(&sp->nntpt);
cb->fname = NULLCHAR;
cb->newnews = NULLCHAR;
rewind(pf);
for(t = 0L; fgets(line,LineLen,pf) != NULLCHAR; t = ftell(pf)) {
if((cp = strchr(line,' ')) == NULLCHAR)
continue; /* something wrong with this line, skip it */
*cp = '\0';
if(strnicmp(line,sp->name,strcspn(line," ")-1) == 0) {
rip2(cp+1);
cb->newnews = strdup(cp+1);
/* Prepare to write back the current host and date */
fseek(pf,t,0);
break;
}
}
if(cb->newnews == NULLCHAR) {
if (Nntpfirstpoll < 0) {
cb->newnews = strdup("900101 000000");
} else { /* from G8FSL */
cb->newnews = mallocw(15);
time(&currtime);
currtime -= Nntpfirstpoll*86400L;
make_time_string(cb->newnews,&currtime);
}
}
fsocket.sin_family = AF_INET;
fsocket.sin_addr.s_addr = cb->dest = sp->dest;
fsocket.sin_port = IPPORT_NNTP;
if((cb->s = socket(AF_INET,SOCK_STREAM,0)) == -1)
goto quit;
sockmode(cb->s,SOCK_ASCII);
if(connect(cb->s,(char *)&fsocket,SOCKSIZE) == -1)
goto quit;
log(cb->s,"Connect NNTP");
time(&currtime);
currtime -= 300L; /* 5 mins rewind bodge against clock errs, G8FSL */
make_time_string(open_time, &currtime);
if(getreply(cb) == -1) /* throw away any hello msg */
goto quit;
/* IHAVE preparation */
if(NnIhave && (cb->ihave = tmpfile()) != NULLFILE) {
sprintf(line,"%s %s",NnIhave == 2 ? "*" : sp->newsgroups,cb->newnews);
if(newnews(line,cb,cb->ihave) < 1) {
fclose(cb->ihave);
cb->ihave = NULLFILE;
}
}
#ifdef LZW
if (LzwActive) {
usprintf(cb->s,"XLZW %d %d\n",Lzwbits,Lzwmode);
if((ret = getreply(cb)) == 235) { /* eat negative response */
lzwinit(cb->s,Lzwbits,Lzwmode);
}
}
#endif
#ifdef XXX
usputs(cb->s,"SLAVE\n");
if(getreply(cb) != 202)
goto quit;
#endif
cb->slave = 1;
if ((f = temp_file(0,1)) == NULLFILE)
goto quit;
usprintf(cb->s,"NEWNEWS %s %s%s\n",
(sp->newsgroups==NULLCHAR ? "*" : sp->newsgroups), cb->newnews,
(GMT_offset ? "" : " GMT") );
if(getreply(cb) != 230) {
goto doihave;
}
if(recv_file(f,cb->s) == -1) {
goto doihave;
}
if ((f1 = temp_file(cb->s,1)) == NULLFILE) {
goto doihave;
}
rewind(f);
for(;;) {
if (fgets(cb->buf,LineLen,f) == NULL)
break;
rip2(cb->buf);
if (strcmp(cb->buf,".") == 0)
break;
if (check_article(cb->buf) != 0)
continue;
usprintf(cb->s,"ARTICLE %s\n",cb->buf);
for (;;) {
if ((r = recvline(cb->s,cb->buf,LineLen)) == -1)
break;
rip2(cb->buf);
if(!isdigit(cb->buf[0])) {
r = -1;
continue;
} else {
r = atoi(cb->buf);
break;
}
}
if(r == -1)
break;
if (r == 220) {
recv_file(f1,cb->s);
rewind(f1);
for ( ;; ) {
if (fgets(cb->buf,LineLen,f1) == NULL)
break;
rip2(cb->buf);
if (strnicmp(cb->buf,msgid,12) == 0) {
cb->id = strdup((strchr(cb->buf,' ')) + 1);
break;
}
}
rewind(f1);
xfer_article2(f1,cb);
free(cb->id);
}
fclose(f1);
if ((f1 = temp_file(cb->s,1)) == NULLFILE)
goto doihave;
pwait(NULL);
}
fclose(f1);
doihave: /* IHAVE offer */
if(NnIhave && cb->ihave != NULLFILE) {
rewind(cb->ihave);
while(fgets(line,sizeof(line),cb->ihave),!feof(cb->ihave)) {
pwait(NULL);
usprintf(cb->s,"IHAVE %s",line);
if((ret = getreply(cb)) == -1)
break;
if(ret != 335)
continue;
rip2(line);
if(doarticlecmd(line,cb) == 0) {
usputs(cb->s,NEol);
if((ret = getreply(cb)) == -1)
break;
continue;
}
if((ret = getreply(cb)) != 235)
continue;
}
fclose(cb->ihave);
}
fclose(f);
quit:
usputs(cb->s,quitcmd);
if (recvline(cb->s,cb->buf,LineLen) == -1);
/*
* update pollfile
*/
if(errno == 0) {
/* Now write back the opening date and time */
fprintf(pf,"%s %s\n", sp->name, open_time);
}
fclose(pf);
close_s(cb->s);
free(cb->newnews);
free((char *)cb);
start_timer(&sp->nntpt);
}
static int
ngmatcha(func,dflt,ngspec,matchlist)
int (*func)(char *,char *);
int dflt;
struct g_list *ngspec;
struct g_list *matchlist;
{
register int match;
char *cp;
struct g_list *m,*n;
match = dflt;
m = matchlist;
for(;;) {
if ((cp = strchr(m->str,'/')) != NULLCHAR)
*cp = '\0';
n = ngspec;
for (;;) {
if (n->str[0] == '!') { /* Handle negation */
if ((*func)(n->str+1, m->str)) {
match = 0;
}
} else {
if ((*func)(n->str, m->str)) {
match = 1;
}
}
if (n->next == NULLG)
break;
else
n=n->next;
}
if (m->next == NULLG)
break;
else
m=m->next;
}
return (match);
}
static int
restreql(w, s)
register char *w;
register char *s;
{
while (*s && *w) {
switch (*w) {
case '*':
for (w++; *s; s++)
if (restreql(w, s))
return 1;
break;
default:
if (*w != *s)
return 0;
w++, s++;
break;
}
}
if (*s)
return 0;
while (*w)
if (*w++ != '*')
return 0;
return 1;
}
/* converts timestring to unix-compatible structure
* str -> YYMMDD HHMMSS [GMT]
* returncode: 0 (!!) if error; > 0 success */
static int32
make_nntime(d,t,str)
struct date *d;
struct time *t;
char *str;
{
register char *cp;
char tmp[3];
int32 tim;
if(str == NULLCHAR)
return 0L;
tmp[2] = '\0';
cp = str;
strncpy(tmp,cp,2);
d->da_year = atoi(tmp)+1900;
if (d->da_year < 1950)
d->da_year += 100; /* next century */
if (d->da_year < 1980)
d->da_year = 1980;
cp+=2;
strncpy(tmp,cp,2);
d->da_mon = atoi(tmp);
if (d->da_mon < 1 || d->da_mon > 12)
return 0L;
cp+=2;
strncpy(tmp,cp,2);
d->da_day = atoi(tmp);
if (d->da_day < 1 || d->da_day > 32)
return 0L;
cp+=3;
strncpy(tmp,cp,2);
t->ti_hour = atoi(tmp);
if (t->ti_hour >=1 && t->ti_hour <= 23 || t->ti_hour==0){
cp+=2;
strncpy(tmp,cp,2);
t->ti_min = atoi(tmp);
}else{
return 0L;
}
if (t->ti_min >= 1 && t->ti_min <= 59 || t->ti_min==0){
cp+=2;
strncpy(tmp,cp,2);
t->ti_sec = atoi(tmp);
}else{
return 0L;
}
if (t->ti_sec >= 1 && t->ti_sec <= 59 || t->ti_sec==0){
t->ti_hund = 0;
tim = dostounix(d,t);
if (*(cp+3) == 'G') tim -= GMT_offset; /* remove bias applied by dostounix */
return tim;
}else{
return 0L;
}
}
/* returncode: -1 if error; 0 if no new news; 1 new news available */
static int
newnews(string,mp,f)
char *string;
struct nntpsv *mp;
FILE *f;
{
register int i,j;
char *cp, *cp1, line[LineLen], groups[LineLen];
struct g_list *ng, *hist, *ngp, *histp, *ptr;
FILE *f1;
int all = 1;
if (check_one(string) == -1)
return -1;
cp = string;
i = 1;
while (*(cp++) > 32)
i++;
if (strlen(cp) < 13)
return -1;
strncpy(groups,string,i-1);
groups[i-1] = '\0';
if(strcmp(groups,"*") != 0)
all = 0;
mp->datest = (struct date *)callocw(1,sizeof(struct date));
mp->timest = (struct time *)callocw(1,sizeof(struct time));
gettime(mp->timest);
getdate(mp->datest);
if ((mp->unixtime = make_nntime(mp->datest,mp->timest,cp)) == 0)
goto quit;
if (mp->unixtime == -1L)
return 0;
if (!all) {
ng = ngp = (struct g_list *)callocw(1,(sizeof(struct g_list)));
cp = groups;
for (;;) {
if ((cp1 = strchr(cp,',')) == NULLCHAR ) {
ng->str = strdup(cp);
ng->next = NULLG;
break;
}
j = strcspn(cp,",");
ng->str = (char *)callocw(1,j+1);
strncpy(ng->str,cp,j);
ng->str[j] = '\0';
ng->next = (struct g_list *)callocw(1,sizeof(struct g_list));
ng = ng->next;
cp1 = strchr(cp,',');
if (cp1 != NULLCHAR)
cp = cp1 + 1;
else
break;
}
}
if ((f1 = open_file(History,READ_TEXT,mp->s,0)) == NULLFILE)
goto quit;
for (;;) {
pwait(NULL);
if (fgets(line,LineLen,f1) == NULL)
break;
rip2(line);
if (!all) {
for(i = 3, cp = line; i; --i)
cp = strchr(cp,' ') + 1;
histp = (struct g_list *)callocw(1,sizeof(struct g_list));
hist = histp;
for (;;) {
if ((cp1 = strchr(cp,' ')) == NULLCHAR) {
hist->str = strdup(cp);
hist->next = NULLG;
break;
}
j = strcspn(cp," ");
hist->str = (char *)callocw(1,j+1);
strncpy(hist->str,cp,j);
hist->str[j] = '\0';
hist->next = (struct g_list *)callocw(1,sizeof(struct g_list));
hist = hist->next;
cp1 = strchr(cp,' ');
if (cp1 != NULLCHAR)
cp = cp1 + 1;
else
break;
}
if (!ngmatcha(restreql,0,ngp,histp)) {
ptr = histp;
for (;;) {
ptr = histp->next;
free(histp->str);
free(histp);
histp = ptr;
if (histp == NULLG)
break;
}
continue;
}
}
cp = strchr(line,' ') + 1;
if ((mp->ftime = make_nntime(mp->datest,mp->timest,cp)) == 0) {
fclose(f1);
goto quit;
}
if ((mp->ftime - mp->unixtime) > 0) {
cp = line;
while ( *cp > 32 )
fputc(*(cp++),f);
fputc('\n',f);
}
if (!all) {
ptr = histp;
for (;;) {
ptr = histp->next;
free(histp->str);
free(histp);
histp = ptr;
if (histp == NULLG)
break;
}
}
}
fclose(f1);
if (!all) {
ptr = ngp;
for (;;) {
ptr = ngp->next;
free(ngp->str);
free(ngp);
ngp = ptr;
if (ngp == NULLG)
break;
}
}
free(mp->datest);
free(mp->timest);
return 1;
quit:
return 0;
}
/* handles incoming newnews-cmd
* returncode: -1 if error; 0 no groups or bad syntax; 1 success */
static int
donewnews(string,mp)
char *string;
struct nntpsv *mp;
{
FILE *f;
int ret;
if((f = temp_file(mp->s,1)) == NULLFILE)
return -1;
ret = newnews(string,mp,f);
switch(ret) {
case -1: /* error in "newnews" routine */
ret = 0;
usputs(mp->s,badsyntax);
break;
case 0: /* no new news */
usputs(mp->s,newnews_t);
usputs(mp->s,NEol);
break;
default: /* new news available, send news file */
rewind(f);
usputs(mp->s,newnews_t);
sendfile(f,mp->s,ASCII_TYPE,0,NULL);
usputs(mp->s,NEol);
ret = 1;
break;
}
fclose(f);
return ret;
}
/* change current newsgroup
* returncode: -1 if error; 0 success; 1 no newsgroup */
static int
dogroup(mp,buf)
struct nntpsv *mp;
char *buf;
{
char *p;
int er;
if((p = strchr(buf,' ')) == NULLCHAR)
return -1;
er = get_path(p,mp);
switch (er) {
case 0:
usputs(mp->s,nogroup);
return 1;
default:
p = strchr(buf,' ');
if (get_pointer(p,mp) == 1) {
usprintf(mp->s,listarticle,
mp->last - mp->first + 1,mp->first,mp->last,strchr(buf,' '));
return 0;
}
case -1:
usputs(mp->s,error);
return -1;
}
}
/* checks if newsgroup is selected
* returncode: -1 no group selected; 0 success */
static int
check_grp(mp)
struct nntpsv *mp;
{
if(mp == NULLNNTPSV || mp->path == NULLCHAR) {
usputs(mp->s,noselect);
return -1;
}
return 0;
}
/* get id-number of message
* returncode: -1 if error; 0 if no message; 1 success */
static int
get_id(bp,mp)
char *bp;
struct nntpsv *mp;
{
FILE *f;
char tmp[LineLen];
if ((f = open_message(mp,NULLFILE)) == NULLFILE)
return 0;
for (;;) {
if (fgets(tmp,LineLen,f) == NULL)
break;
if (check_blank(tmp))
break;
if (strnicmp(tmp,msgid,12)==0) {
fclose(f);
strcpy(bp,strchr(tmp,' '));
rip2(bp);
return 1;
}
}
fclose(f);
strcpy(bp,"\0");
return 0;
}
/* gets next news of newsgroup
* returncode: -1 if error; 0 no news; 1 success */
static int
get_next(mp)
struct nntpsv *mp;
{
FILE *f;
for (;;) {
if (mp->pointer == 0 ) {
usputs(mp->s,nonext);
return 0;
}
if (++(mp->pointer) > mp->last) {
mp->pointer--;
usputs(mp->s,nonext);
return 0;
}
sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
if ((f = open_file(mp->buf,READ_TEXT,mp->s,0)) != NULLFILE) {
fclose(f);
return 1;
}
}
}
/* gets last news of newsgroup
* returncode: -1 if error; 0 no news; 1 success */
static int
get_last(mp)
struct nntpsv *mp;
{
FILE *f;
for (;;) {
if (mp->pointer == 0) {
usputs(mp->s,noprev);
return 0;
}
if (--(mp->pointer) < mp->first) {
mp->pointer++;
usputs(mp->s,noprev);
return 0;
}
sprintf(mp->buf,"%s/%u",mp->path,mp->pointer);
if ((f = open_file(mp->buf,READ_TEXT,mp->s,0)) != NULLFILE) {
fclose(f);
return 1;
}
}
}
/*
* Retrieves article by message-id. Sets mp->pointer and mp->path.
* Return: success 0, no article 1, error -1.
*/
static int
retr_by_mid(mid,mp)
char *mid;
struct nntpsv *mp;
{
FILE *f;
char *p,*p1,line[LineLen];
if((f = open_file(History,READ_TEXT,mp->s,0)) == NULLFILE)
return -1;
for(;;) {
if(fgets(line,LineLen-1,f) == NULLCHAR) {
usputs(mp->s,noart);
fclose(f);
return 1;
}
if(strncmp(line,mid,strlen(mid)) == 0)
break;
}
p = strchr(line,' ') + 14; /* point to the space before first newsgroup */
p1 = strchr(p,'/');
*p1 = '\0';
p1++;
mp->pointer = atoi(p1); /* get the article number */
if(mp->path != NULLCHAR)
free(mp->path);
if(strcmp(p,"JUNK") == 0)
mp->path = strdup(Forward);
else
get_path(p,mp);
fclose(f);
return 0;
}
/*
* Retrieves article by article number. Sets mp->pointer.
* Return: success 0, no article 1, error -1.
*/
static int
retr_by_num(buf,mp)
char *buf;
struct nntpsv *mp;
{
int n;
char *p;
if(check_grp(mp))
return 1;
if((p = strchr(buf,' ')) == NULLCHAR || check_blank(p))
return 0;
p++;
n = atoi(p);
if(!n || n > mp->last || n < mp->first) {
usputs(mp->s,noart);
return 1;
}
mp->pointer = n;
return 0;
}
/*
* Do ARTICLE command. Return: success 0, no article 1, error -1.
*/
static int
doarticlecmd(buf,mp)
char *buf;
struct nntpsv *mp;
{
FILE *f;
char *p,*hold_s;
int ret,hold_i,hold = 0;
if((p = strchr(buf,'<')) != NULLCHAR) {
hold = 1;
hold_i = mp->pointer;
hold_s = mp->path;
mp->path = NULLCHAR;
if((ret = retr_by_mid(p,mp)) != 0)
return ret;
}
else if((ret = retr_by_num(buf,mp)) != 0)
return ret;
if (get_id(mp->buf,mp) != 1)
return -1;
f = NULL; /* WG7J */
if ((f = open_message(mp,f)) == NULLFILE)
return -1;
usprintf(mp->s,retrieve,mp->pointer,mp->buf,artmsg);
sendfile(f, mp->s, ASCII_TYPE,0,NULL);
usputs(mp->s,NEol);
if(hold) {
mp->pointer = hold_i;
free(mp->path);
mp->path = hold_s;
}
fclose(f);
return 0;
}
/*
* Do HEAD command. Return: success 0, no article 1, error -1.
*/
static int
doheadcmd(buf,mp)
char *buf;
struct nntpsv *mp;
{
FILE *f;
char *p,*hold_s;
int ret,hold_i,hold = 0;
if((p = strchr(buf,'<')) != NULLCHAR) {
hold = 1;
hold_i = mp->pointer;
hold_s = mp->path;
mp->path = NULLCHAR;
if((ret = retr_by_mid(p,mp)) != 0)
return ret;
}
else if((ret = retr_by_num(buf,mp)) != 0)
return ret;
if (get_id(mp->buf,mp) != 1)
return 1;
f = NULL; /* WG7J */
if ((f = open_message(mp,f)) == NULLFILE)
return -1;
usprintf(mp->s,head,mp->pointer,mp->buf,artmsg);
while(fgets(mp->buf,LineLen-1,f) != NULLCHAR) {
if(check_blank(mp->buf))
break;
usputs(mp->s,mp->buf);
}
usputs(mp->s,NEol);
if(hold) {
mp->pointer = hold_i;
free(mp->path);
mp->path = hold_s;
}
fclose(f);
return 0;
}
/*
* Do BODY command. Return: success 0, no article 1, error -1.
*/
static int
dobodycmd(buf,mp)
char *buf;
struct nntpsv *mp;
{
FILE *f;
char *p,*hold_s;
int ret,hold_i,hold = 0, got;
if((p = strchr(buf,'<')) != NULLCHAR) {
hold = 1;
hold_i = mp->pointer;
hold_s = mp->path;
mp->path = NULLCHAR;
if((ret = retr_by_mid(p,mp)) != 0)
return ret;
}
else if((ret = retr_by_num(buf,mp)) != 0)
return ret;
if (get_id(mp->buf,mp) != 1)
return 1;
f = NULL; /* WG7J */
if ((f = open_message(mp,f)) == NULLFILE)
return -1;
usprintf(mp->s,body,mp->pointer,mp->buf,artmsg);
got = 0;
while(fgets(mp->buf,LineLen-1,f) != NULLCHAR) {
if(got)
usputs(mp->s,mp->buf);
if(check_blank(mp->buf))
got = 1;
}
usputs(mp->s,NEol);
if(hold) {
mp->pointer = hold_i;
free(mp->path);
mp->path = hold_s;
}
fclose(f);
return 0;
}
/*
* Do STAT command. Return: success 0, no article 1, error -1.
*/
static int
dostatcmd(buf,mp)
char *buf;
struct nntpsv *mp;
{
char *p,*hold_s;
int ret,hold_i,hold = 0;
if((p = strchr(buf,'<')) != NULLCHAR) {
hold = 1;
hold_i = mp->pointer;
hold_s = mp->path;
mp->path = NULLCHAR;
if((ret = retr_by_mid(p,mp)) != 0)
return ret;
}
else if((ret = retr_by_num(buf,mp)) != 0)
return ret;
if (get_id(mp->buf,mp) != 1)
return 1;
usprintf(mp->s,statistics,mp->pointer,mp->buf,artmsg);
if(hold) {
mp->pointer = hold_i;
free(mp->path);
mp->path = hold_s;
}
return 0;
}
/*
* Do XHDR command. Return: success 0, no article 1, error -1.
*/
static int
doxhdrcmd(buf,mp)
char *buf;
struct nntpsv *mp;
{
FILE *f;
char *path,*fld,*p,*mid,line[LineLen];
int pointer,start,stop,ret = 0;
if((fld = strchr(buf,' ')) == NULLCHAR || check_blank(fld)) {
usputs(mp->s,badsyntax);
return -1;
}
while(isspace(*++fld));
pointer = start = stop = mp->pointer;
path = mp->path;
mid = mp->path = NULLCHAR;
if((p = strchr(fld,' ')) != NULLCHAR && !check_blank(p)) {
*p = '\0';
while(isspace(*++p));
if(*p == '<') {
if((ret = retr_by_mid(p,mp)) != 0)
goto quit;
start = stop = mp->pointer;
mid = p;
} else {
start = stop = atoi(p);
if((p = strchr(p,'-')) != NULLCHAR)
stop = atoi(++p);
}
}
if(!mid) {
mp->path = strdup(path);
if(check_grp(mp)) {
ret = 1;
goto quit;
}
usprintf(mp->s,xheader1,fld);
} else
usprintf(mp->s,xheader2,0,fld,p);
while(start <= stop) {
if(mid || (start >= mp->first && start <= mp->last)) {
sprintf(line,"%s/%u",mp->path,start);
if((f = open_file(line,READ_TEXT,0,0)) != NULLFILE) {
for(;;) {
if(fgets(line,LineLen-1,f) == NULLCHAR
|| check_blank(line)) { /* no match was found */
if(mid)
usprintf(mp->s,"%s (none)\n",mid);
else
usprintf(mp->s,"%d (none)\n",start);
break;
}
if((p = strchr(line,':')) != NULLCHAR)
*p = '\0';
if(stricmp(line,fld) == 0) {
if(mid)
usprintf(mp->s,"%s %s",mid,p + 2);
else
usprintf(mp->s,"%d %s",start,p + 2);
break;
}
}
fclose(f);
}
}
start++;
}
usputs(mp->s,NEol);
quit:
mp->pointer = pointer;
free(mp->path);
mp->path = path;
return ret;
}
/*
* Do XOVER command. Return: success 0, error -1.
*/
static int
doxovercmd(buf,mp)
char *buf;
struct nntpsv *mp;
{
FILE *f;
char *subject,*from,*date,*mid,*ref,*xref,*p,line[LineLen];
int lines,size,start,stop,got;
if((p = strchr(buf,' ')) != NULLCHAR) {
start = stop = atoi(p);
if((p = strchr(buf,'-')) != NULLCHAR)
stop = atoi(++p);
} else
start = stop = mp->pointer;
usputs(mp->s,xover);
while(start <= stop) {
if(start >= mp->first && start <= mp->last) {
sprintf(line,"%s/%u",mp->path,start);
if((f = open_file(line,READ_TEXT,0,0)) != NULLFILE) {
subject = from = date = mid = ref = xref = NULLCHAR;
lines = size = got = 0;
while(fgets(line,LineLen-1,f) != NULLCHAR) {
rip2(line);
if(got == 0) {
if(strnicmp(line,subj,9) == 0)
subject = strdup(strchr(line,' ') + 1);
else if(strnicmp(line,frm,6) == 0)
from = strdup(strchr(line,' ') + 1);
else if(strnicmp(line,dte,6) == 0)
date = strdup(strchr(line,' ') + 1);
else if(strnicmp(line,msgid,12) == 0)
mid = strdup(strchr(line,' ') + 1);
else if(strnicmp(line,"Lines: ",7) == 0)
lines = atoi(strchr(line,' ') + 1);
else if(strnicmp(line,"References: ",12) == 0)
ref = strdup(strchr(line,' ') + 1);
} else
size += strlen(line);
if(*line == '\0')
got = 1;
}
usprintf(mp->s,"%u\t%s\t%s\t%s\t%s\t%s\t%u\t%u\t%s\n",
start,subject,from,date,mid, /* these must be present */
ref ? ref : "",
size,lines,
""); /* last field not (yet) implemented */
free(subject);
free(from);
free(date);
free(mid);
free(ref);
fclose(f);
}
}
start++;
}
usputs(mp->s,NEol);
return 0;
}
/* Checks and rewrites message headers if needed. Returns -1 if error,
* 0 if all RFC1036 headers are present and 1 if a subset of RFC1036
* headers is present. (1 means that IHAVE should be rejected but
* POST is ok.)
*/
static int
garbled(inf,outf)
FILE *inf;
FILE *outf;
{
char line[LineLen],*cp;
int got,ok,lines,ret;
long currtime;
got = ok = lines = 0;
/* first scan the headers */
rewind(inf);
while(fgets(line,LineLen,inf) != NULLCHAR) {
if(got) {
lines++;
continue;
}
rip2(line);
if (check_blank(line)) { /* end of headers */
got = 1;
continue;
}
if (line[0] == ' ' || line[0] == '\t') /* continuation header */
continue;
cp = line;
while (*cp != '\0' && *cp != ' ' && *cp != ':')
cp++;
if (*cp != ':' || *++cp != ' ')
return -1; /* bad header; reject article */
cp++;
if (check_blank(cp)) /* empty header */
continue;
if (!strnicmp(line,frm,6))
ok |= 1;
if (!strnicmp(line,subj,9))
ok |= 2;
if (!strnicmp(line,ngrps,12))
ok |= 4;
if (!strnicmp(line,dte,6))
ok |= 8;
if (!strnicmp(line,msgid,12))
if (check_article(cp) == 0)
ok |= 16;
if (!strnicmp(line,pth,6))
ok |= 32;
if (!strnicmp(line,"Lines: ",7))
ok |= 64;
}
if((ok & 7) != 7) /* From, Subject and Newsgroups not found */
return -1;
if(ok == 63)
ret = 0; /* everything ok */
else
ret = 1;
/* then rewrite if necessary */
got = 0;
rewind(inf);
while(fgets(line,LineLen,inf) != NULLCHAR) {
pwait(NULL);
if(got) {
fputs(line,outf);
continue;
}
if(check_blank(line)) {
got = 1;
if(!(ok & 64))
fprintf(outf,"Lines: %d\n\n",lines);
continue;
}
if(line[0] != ' ' && line[0] != '\t') {
cp = strchr(line,':');
cp++;
if(check_blank(cp)) /* empty header; do not copy */
continue;
}
if(!strnicmp(line,"Xref: ",6) ||
!strnicmp(line,"Date-Received: ",15) ||
!strnicmp(line,"Posted: ",8) ||
!strnicmp(line,"Posting-Version: ",17) ||
!strnicmp(line,"Received: ",10) ||
!strnicmp(line,"Relay-Version: ",15))
continue; /* do not copy these headers */
fputs(line,outf);
rip2(line);
/* no path? */
if (!(ok & 32) && strnicmp(line,frm,6) == 0) {
fprintf(outf,"%snot-for-mail\n",pth);
ok |= 32;
}
if (strnicmp(line,subj,9) == 0) {
/* no msgid? */
if (!(ok & 16)) {
fprintf(outf,"%s<%ld@%s>\n",msgid,get_msgid(),Hostname);
ok |= 16;
}
/* no date? */
if (!(ok & 8)) {
time(&currtime);
fprintf(outf,"%s%s",dte,ptime(&currtime));
ok |= 8;
}
}
}
rewind(outf);
return ret;
}
/* returncode: -1 if error; 0 success */
static int
get_article2(mp, id)
struct nntpsv *mp;
char *id;
{
FILE *f,*f1;
int ret = -1;
if((f = temp_file(0,1)) == NULLFILE)
return -1;
if((f1 = temp_file(0,1)) == NULLFILE) {
fclose(f);
return -1;
}
mp->ap = (struct article *)callocw(1,sizeof(struct article));
mp->id = (*id) ? strdup(id) : strdup(">");
usputs(mp->s,sendart);
if(recv_file(f,mp->s) == (-1)) {
free((struct article *)mp->ap);
goto quit;
}
if (garbled(f,f1) != 0) {
usputs(mp->s,transnotok);
free((struct article *)mp->ap);
goto quit;
}
if(xfer_article2(f1,mp) < 1)
usputs(mp->s,transnotok);
else {
ret = 0;
usputs(mp->s,transok);
}
quit:
fclose(f);
fclose(f1);
return ret;
}
/*
* Do a POST -command. Returns 0 if success.
*/
static int
post_article(mp)
struct nntpsv *mp;
{
FILE *f,*f1;
int ret = -1;
char *p,*p1;
if((f = temp_file(0,1)) == NULLFILE)
return -1;
if((f1 = temp_file(0,1)) == NULLFILE) {
fclose(f);
return -1;
}
usputs(mp->s,sendpost);
if(recv_file(f,mp->s) == (-1))
goto quit;
if (garbled(f,f1) < 0) {
usprintf(mp->s,"%s - header garbled\n",postfailed);
goto quit;
}
rewind(f1);
while (fgets(mp->buf,LineLen,f1) != NULL) {
rip2(mp->buf);
if (strnicmp(mp->buf,msgid,12) == 0) {
mp->id = strdup((strchr(mp->buf,' ')) + 1);
break;
}
}
rewind(f1);
if(xfer_article2(f1,mp) < 1)
usprintf(mp->s,"%s\n",postfailed);
else
usputs(mp->s,postok);
quit:
fclose(f1);
fclose(f);
return 0;
}
void
poll(p)
void *p;
{
if (newproc("NNTP Client", 2048, nntppoll, 0, p, NULL, 0) == NULLPROC)
start_timer(&((struct Servers *)p)->nntpt); /* N5KNX: retry later */
}
static int
chk_access(s)
int s;
{
struct sockaddr fsocket;
FILE *f;
int trans,verb,i;
int access = -1; /* default is no access */
char *cp,*cp1,name[80], line[80];
trans = DTranslate; /* save the old state */
verb = DVerbose;
DTranslate = 1; /* force the output of psocket() to be literal */
DVerbose = 1;
i = SOCKSIZE;
if(getpeername(s,(char *)&fsocket,&i) != -1) {
strcpy(name,psocket(&fsocket));
if((cp = strchr(name,':')) != NULLCHAR)
*cp = '\0';
}
DTranslate = trans; /* restore the old state */
DVerbose = verb;
if((f = open_file(Naccess,READ_TEXT,s,0)) != NULLFILE) {
while(fgets(line,79,f) != NULLCHAR) {
if(*line == '#')
continue;
if((cp = strchr(line,':')) != NULLCHAR)
*cp = '\0';
if(wildmat(name,line,NULLCHARP)) {
if((cp1 = strchr(++cp,':')) != NULLCHAR)
*cp1 = '\0';
if(strchr(cp,'R')) /* read only */
access = 0;
if(strchr(cp,'P')) /* read and post */
access = 1;
break;
}
}
fclose(f);
}
return access;
}
static void
nntpserv(s,unused,p)
int s;
void *unused;
void *p;
{
struct nntpsv *mp;
FILE *fp;
long t;
int cnt, postallowed = 1;
char **cmdp, *arg, *cp, *cmd, buf[LineLen];
#ifdef LZW
int lbits, lmode;
#endif
sockmode(s,SOCK_ASCII);
sockowner(s,Curproc); /* We own it now */
log(s,"open NNTP");
if (!Filecheck)
if(check_system()) {
usprintf(s,fatal,"STRUCTURE");
log(s,"NNTP error - FILE STRU");
close_s(s);
return;
}
if((mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv))) == NULLNNTPSV) {
usputs(s,Nospace);
close_s(s);
return;
}
if(Nntpaccess)
if((postallowed = chk_access(s)) < 0) {
usputs(s,noaccess);
close_s(s);
return;
}
mp->s = s;
mp->debug = 0;
mp->path = NULLCHAR;
time(&t);
cp = ctime(&t);
cp[24] = '\0';
usprintf(s,nnversion,postallowed ? "0" : "1",Host,Version,cp,
postallowed ? "(posting ok)" : "(no posting)");
loop:
if ((cnt = recvline(s,buf,LineLen)) == -1) {
/* He closed on us */
goto quit;
}
if(check_blank(buf))
goto loop; /* empty line, do nothing */
rip2(buf);
cmd = buf;
/* Translate entire buffer to lower case */
for(cp = cmd; *cp != '\0' ;cp++) {
if ( *cp == ' ' ) break;
*cp = tolower(*cp);
}
/* Find command in table; if not present, return syntax error */
/* If not present, return 500 command unrecognized */
for(cmdp = commands; *cmdp != NULLCHAR; cmdp++)
if(strnicmp(*cmdp,cmd,min(strlen(*cmdp),strlen(cmd))) == 0)
break;
if(*cmdp == NULLCHAR){
usputs(mp->s,notrecognd);
goto loop;
}
arg = &cmd[strlen(*cmdp)];
/* Skip spaces after command */
while(*arg == ' ')
arg++;
/* Execute specific command */
switch(cmdp - commands) {
case XLZW_CMD:
#ifdef LZW
if (LzwActive) {
usputs(mp->s,transok);
cp = strchr(arg,' ');
*cp++ = '\0';
lbits = atoi(arg); /*get lzwbits*/
lmode = atoi(cp);
lzwinit(mp->s,lbits,lmode);
} else
#endif
usputs(mp->s,error);
break;
case QUIT_CMD:
goto quit;
case NEWNEWS_CMD:
if ((cp = strchr(buf,' ')) == NULLCHAR) {
usputs(mp->s,badsyntax);
break;
}
cp++;
donewnews(cp,mp);
break;
case IHAVE_CMD:
if ((cp = strchr(buf,'<')) == NULLCHAR) {
usputs(mp->s,badsyntax);
break;
}
if (check_article(cp) != 0) {
usputs(mp->s,notwanted);
break;
}
if(get_article2(mp,cp))
goto quit;
break;
case POST_CMD:
if (!postallowed) {
usputs(mp->s,notallowed);
break;
}
post_article(mp);
break;
case HELP_CMD:
usprintf(mp->s,"100 %s - help follows:\n",Host);
if ((fp = open_file(Nhelp,READ_TEXT,0,0)) != NULLFILE ) {
sendfile(fp,mp->s,ASCII_TYPE,0,NULL);
fclose(fp);
} else {
usprintf(mp->s,"\nKA9Q NOS NNTP Server, version %s\n\n",Version);
for(cnt = 1;commands[cnt] != NULLCHAR;cnt++)
usprintf(mp->s,"%-9s%c",commands[cnt],(cnt%7) ? ' ' : '\n');
usputs(mp->s,"\n");
}
usputs(mp->s,NEol);
break;
case XINFO_CMD:
if ((fp = open_file(NInfo,READ_TEXT,0,0)) != NULLFILE ) {
usprintf(mp->s,"100 %s - xinfo follows:\n",Host);
sendfile(fp,mp->s,ASCII_TYPE,0,NULL);
fclose(fp);
} else {
usputs(mp->s,xinfo);
}
usputs(mp->s,NEol);
break;
case LIST_CMD:
if ((fp = open_file(Active,READ_TEXT,mp->s,0)) != NULLFILE) {
usputs(mp->s,listgroups);
sendfile(fp,mp->s,ASCII_TYPE,0,NULL);
fclose(fp);
usputs(mp->s,NEol);
}
break;
case NEWGROUPS_CMD:
usputs(mp->s, newgroups);
usputs(mp->s, NEol); /* empty list, as it's NOT IMPLEMENTED */
break;
case GROUP_CMD :
dogroup(mp,buf);
break;
case HEAD_CMD :
doheadcmd(buf,mp);
break;
case BODY_CMD :
dobodycmd(buf,mp);
break;
case STAT_CMD :
dostatcmd(buf,mp);
break;
case ARTICLE_CMD :
doarticlecmd(buf,mp);
break;
case XHDR_CMD :
doxhdrcmd(buf,mp);
break;
case XOVER_CMD :
if (check_grp(mp))
break;
doxovercmd(buf,mp);
break;
case NEXT_CMD :
if (check_grp(mp))
break;
if (get_next(mp) == 1) {
if (get_id(buf,mp) == 1)
usprintf(mp->s,sepcmd,mp->pointer,&buf[1],artmsg);
break;
}
break;
case LAST_CMD :
if (check_grp(mp))
break;
if (get_last(mp) == 1 ) {
if (get_id(buf,mp) == 1)
usprintf(mp->s,sepcmd,mp->pointer,&buf[1],artmsg);
break;
}
break;
/* This two following cmds currently are not used for much */
case DEBUG_CMD:
mp->debug = (mp->debug == 0) ? 1 : 0;
usprintf(mp->s,debug,(mp->debug == 0) ? "OFF" : "ON");
break;
case SLAVE_CMD :
mp->slave = (mp->slave == 0) ? 1 : 0;
usprintf(mp->s,slave,(mp->slave == 0) ? "OFF" : "ON");
break;
}
goto loop;
quit:
usputs(mp->s,closing);
log(mp->s,"close NNTP");
close_s(mp->s);
if(mp->path != NULLCHAR)
free(mp->path);
if(mp->newnews != NULLCHAR)
free(mp->newnews);
if(mp->fname != NULLCHAR)
free(mp->fname);
if(mp->id != NULLCHAR);
free(mp->id);
free((char *)mp);
}
/* ---------------------------- NNTP-GATE --------------------------- */
static char * near
mkreplypath(FILE *data)
{
char buf[LineLen], *cp, *cp1, *path;
sprintf(buf,"%sNNTP_GATE@%s",pth,Hostname);
path = strdup(buf);
rewind(data);
while((fgets(buf,LineLen,data)) != 0) {
if(htype(buf) == DATE)
break;
if(htype(buf) == RECEIVED) {
cp = strchr(buf,' ');
cp++;
cp = strchr(cp, ' ');
cp++;
cp1 = strpbrk(cp, ". \0");
*cp1 = '\0';
cp1 = mallocw(strlen(path)+strlen(cp)+2); /* */
sprintf(cp1,"%s!%s",path,cp);
free(path);
path = cp1;
}
}
return(path);
}
int
nnGpost(FILE *data,char *from,struct list *le)
{
struct nntpsv *mp;
char buf[LineLen], *cp;
FILE *f, *idf;
int32 id;
int strl;
long currtime;
if (!Filecheck)
if(check_system())
return -1;
if ((f = temp_file(0,1)) == NULLFILE)
return -1;
mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv));
/* build postuser */
cp = mkreplypath(data);
fprintf(f,"%s\n",cp);
free((char *)cp);
fprintf(f,"%s%s\n",frm,from);
/*-----------------------------------------------------------------*
* build newsgroup *
*-----------------------------------------------------------------*/
if((cp = strchr(le->val,'@')) != NULLCHAR)
*cp = '\0';
strcpy(buf,le->val);
cp=buf;
strl = strlen(cp);
while(*cp != '\0') {
if(*cp == '!') *cp = '.'; /* change ! into . - yc1dav */
cp++;
}
fprintf(f,"%s%s\n",ngrps,(cp-strl+1)); /* skip the first "." */
/*-----------------------------------------------------------------*
* find the subject
*-----------------------------------------------------------------*/
rewind (data);
while((fgets(buf,sizeof(buf),data))!=0) {
if (htype(buf)== SUBJECT)
break;
continue;
}
fputs((*buf == 0) ? "Subject: (none)\n" : buf,f);
/*--------------------------------------------------------------------*
* use msgid of original message
*--------------------------------------------------------------------*/
rewind(data);
while((fgets(buf,sizeof(buf),data))!=0) {
if (htype(buf)== MSGID)
break;
continue;
}
if (*buf == 0) {
sprintf(buf,"%s/sequence.seq",Mailqdir);
idf = open_file(buf,"r+",0,1);
id = atol(fgets(buf,LineLen,idf));
rewind(idf);
fprintf(idf,"%ld",id+1);
fclose(idf);
fprintf(f,"%s<%ld@%s>\n",msgid,id,Hostname);
sprintf(mp->buf,"<%ld@%s>",id,Hostname);
} else {
fputs(buf,f);
rip(buf);
cp = strchr(buf,'<');
strcpy(mp->buf,cp);
if (check_article(mp->buf))
goto quit;
}
rewind (data);
time(&currtime);
fprintf(f,"Sender: NNTP@%s\n",Hostname);
/*--------------------------------------------------------------------*
* message follows *
*--------------------------------------------------------------------*/
fputs("Comments: Message transferred from SMTP\n",f);
while((fgets(buf,sizeof(buf),data))!=0) {
switch(htype(buf)) {
case FROM:
case MSGID:
case RECEIVED:
fgets(buf,sizeof(buf),data); /*eat the id*/
continue;
}
fputs(buf,f);
}
rewind(f);
mp->id = strdup(mp->buf);
xfer_article2(f,mp);
/*
*
* log(-1,"NNGT: transfer: Msg %s",mp->id);
*
*/
quit:
fclose(f);
free(mp);
return 0;
}
/* ---------------------------- Servercmd --------------------------- */
/* Start up NNTP receiver service */
int
nntp1(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int16 port;
if(check_system() == -1)
return -1;
if(argc < 2)
port = IPPORT_NNTP;
else
port = atoi(argv[1]);
return start_tcp(port,"NNTP Server",nntpserv,2048);
}
/* Shutdown NNTP service (existing connections are allowed to finish) */
int
nntp0(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int16 port;
if(argc < 2)
port = IPPORT_NNTP;
else
port = atoi(argv[1]);
return stop_tcp(port);
}
/* ---------------------------- Subcmds --------------------------- */
/* lists active newsgroups
* returncode: -1 if error; 0 success */
static int
donnactive(argc,argv,p)
int argc;
char *argv[];
void *p;
{
FILE *fp;
char line[80], *cp;
if((fp = open_file(Active,READ_TEXT,0,1)) == NULLFILE)
return -1;
tputs("Msg# next mod newsgroup\n");
for(;;) {
if (fgets(line,sizeof(line),fp) == NULL)
break;
if((cp = strchr(line,' ')) == NULLCHAR)
break;
*cp = '\0';
rip(++cp);
tprintf("%s %s\n",cp,line);
pwait(NULL);
}
fclose(fp);
return 0;
}
static int
donnaccess(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Nntpaccess,"NNTP access",argc,argv);
}
/* add nntp servers to list */
static int
donnadds(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct Servers *np;
for(np = Nntpserver; np != NULLSERVER; np = np->next)
if(stricmp(np->name,argv[1]) == 0)
break;
if (np == NULLSERVER) {
np = (struct Servers *)callocw(1,sizeof(struct Servers));
if((np->dest = resolve(argv[1])) == 0) {
tprintf(Badhost,argv[1]);
free((char *)np);
return -1;
}
np->name = strdup(argv[1]);
np->next = Nntpserver;
Nntpserver = np;
np->newsgroups = NULLCHAR;
np->lowtime = np->hightime = -1;
np->nntpt.func = poll; /* what to call on timeout */
np->nntpt.arg = (void *)np;
}
if (argc > 3) {
int i;
if (np->newsgroups == NULLCHAR) {
np->newsgroups = callocw(1,LineLen);
*np->newsgroups = '\0';
}
for (i = 3; i < argc; ++i) {
if (isdigit(*argv[i])) {
int lh, ll, hh, hl;
sscanf(argv[i], "%d:%d-%d:%d", &lh, &ll, &hh, &hl);
np->lowtime = lh * 100 + ll;
np->hightime = hh * 100 + hl;
} else if ((strlen(np->newsgroups)+strlen(argv[i])+2) >= LineLen)
tprintf("To many groups, '%s' ignored\n", argv[i]);
else { /* it's a group, and it fits... add it to list */
if (*np->newsgroups != '\0')
strcat(np->newsgroups, ",");
strcat(np->newsgroups, argv[i]);
}
}
if (*np->newsgroups == '\0') { /* No groups specified? */
free(np->newsgroups);
np->newsgroups = NULLCHAR;
}
}
/* set timer duration */
set_timer(&np->nntpt,atol(argv[2])*1000L);
start_timer(&np->nntpt); /* and fire it up */
return 0;
}
static int
donnfirstpoll(argc,argv,p) /* from G8FSL */
int argc;
char *argv[];
void *p;
{
return setint(&Nntpfirstpoll,"NNTP polls new server for news over last <n> days",argc,argv);
}
/* create a new newsgroup */
static int
donncreate(argc,argv,p)
int argc;
char *argv[];
void *p;
{
FILE *f,*t;
char line[LineLen];
int n;
if ((f = open_file(Active,READ_TEXT,0,1)) == NULL)
return -1;
if ((t = temp_file(0,1)) == NULL) {
fclose(f);
return -1;
}
while (fgets(line,LineLen,f) != NULL) {
fputs(line,t);
n = strcspn(line," ");
line[n] = '\0';
if (strcmp(line,argv[1]) == 0) {
tprintf("Newsgroup %s already exists.\n",argv[1]);
goto quit;
}
}
rewind(t);
fclose(f);
if (argc > 2 && *argv[2] == 'n')
n = 1;
else
n = 0;
if (!make_path(argv[1])) {
if ((f = open_file(Active,WRITE_TEXT,0,1)) == NULL) {
fclose(t);
return -1;
}
while (fgets(line,LineLen,t) != NULL)
fputs(line,f);
fprintf(f,"%s 00000 00001 %c\n",argv[1],(n ? 'n' : 'y'));
}
quit:
fclose(f);
fclose(t);
return 0;
}
/* drops nntp servers from list */
static int
donndrops(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct Servers *np, *npprev = NULLSERVER;
for(np = Nntpserver; np != NULLSERVER; npprev = np, np = np->next)
if(stricmp(np->name,argv[1]) == 0) {
stop_timer(&np->nntpt);
free(np->name);
if (np->newsgroups)
free(np->newsgroups);
if(npprev != NULLSERVER)
npprev->next = np->next;
else
Nntpserver = np->next;
free((char *)np);
return 0;
}
tputs("No such server enabled.\n");
return -1;
}
/* copies a news from given newsgroup to the mailbox */
static int
donndump(argc,argv,p)
int argc;
char *argv[];
void *p;
{
FILE *t, *f, *o;
char *path, *line, *cp, newsname[25], *cp1;
struct ffblk blk;
if (!Filecheck)
if(check_system())
return -1;
if ((f = open_file(Pointer,READ_TEXT,0,1)) == NULLFILE)
return 0;
path = mallocw(LineLen);
line = mallocw(LineLen);
*path = *line = '\0';
for(;;) {
if (fgets(line,LineLen,f) == NULL)
break;
if (!strncmp(line,argv[1],strlen(argv[1]))) {
cp = strchr(line,' ') + 1;
strcpy(path,cp);
break;
}
pwait(NULL);
}
fclose(f);
if (*path == '\0') {
tprintf("No newsgroup %s\n",argv[1]);
goto error;
}
rip2(path);
cp = strrchr(path,'/');
cp1 = &newsname[0];
while(*cp)
*(cp1++) = *(cp++);
*cp1 = '\0';
strcpy(line,path);
strcat(line,"/*.*");
if(findfirst(line,&blk,0)) {
tputs("No news in newsgroup\n");
goto error;
}
if(argc > 2)
sprintf(newsname,"/%s",argv[2]);
sprintf(line,"%s%s.txt",Mailspool,newsname);
if ((o = open_file(line,"a+",0,1)) == NULLFILE)
goto error;
if(!(mlock(Mailspool,newsname))) {
tprintf("Newsgroup dump to %s\n",line);
for (;;) {
if((t = temp_file(0,1)) == NULLFILE) {
fclose(o);
goto error;
}
sprintf(line,"%s/%s",path,blk.ff_name);
/* Open the article */
if ((f = open_file(line,READ_TEXT,0,1)) == NULLFILE) {
fclose(t);
fclose(o);
goto error;
}
pwait(NULL);
tputc('.'); /* One dot/article processed */
tflush();
for (;;) {
if (fgets(line,LineLen,f) == NULL)
break;
fputs(line,t);
if (!strnicmp(line,frm,6)) {
cp = strchr(line,' ')+1;
fprintf(o,"From %s",cp);
}
}
rewind(t);
for(;;) {
if (fgets(line,LineLen,t) == NULL)
break;
fputs(line,o);
}
fputc('\n',o);
fclose(t);
fclose(f);
if (findnext(&blk))
break;
}
rmlock(Mailspool,newsname);
} else
tputs("Mailfile is busy, try later");
fclose(o);
tputs("\n");
error:
free(line);
free(path);
return 0;
}
static int
donnkick(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct Servers *np;
for(np = Nntpserver; np != NULLSERVER; np = np->next)
if(!stricmp(np->name,argv[1])) {
/* If the timer is not running, the timeout function has
* already been called and we don't want to call it again.
*/
if(run_timer(&np->nntpt) || dur_timer(&np->nntpt) == 0) {
stop_timer(&np->nntpt);
poll((void *)np);
}
return 0;
}
tputs("No server enabled\n");
return 0;
}
#ifdef LZW
/* sets LzwActive flag */
static int
donnlzw(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&LzwActive,"NNTP LZW",argc,argv);
}
#endif
/* list nntp servers */
static int
donnlists(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct Servers *np;
char tbuf[80];
for(np = Nntpserver; np != NULLSERVER; np = np->next) {
if (np->lowtime != -1 && np->hightime != -1)
sprintf(tbuf, " -- %02d:%02d-%02d:%02d",
np->lowtime/100, np->lowtime%100,
np->hightime/100, np->hightime%100);
else
tbuf[0] = '\0';
tprintf("%-32s (%lu/%lu%s)\n Groups: %s\n", np->name,
read_timer(&np->nntpt) /1000L,
dur_timer(&np->nntpt) /1000L,
tbuf, np->newsgroups ? np->newsgroups : "");
}
return 0;
}
/* manually entering new news
* returncode: -1 if error; 0 success */
static int
donnpost(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct session *sp;
struct nntpsv *mp;
char buf[LineLen];
long id;
FILE *f, *idf, *ufp;
long currtime;
if (!Filecheck)
if(check_system())
return -1;
if((sp = newsession("Post",0,1)) == NULLSESSION)
return -1;
mp = (struct nntpsv *)callocw(1,sizeof(struct nntpsv));
for (;;) {
if ((f = temp_file(0,1)) == NULLFILE)
goto done;
id = get_msgid();
if (Post->user == NULLCHAR) {
tputs("User name? ");
recvline(sp->input,buf,LineLen);
rip2(buf);
Post->user = strdup(buf);
}
fprintf(f,"%s%s\n",pth,Post->user);
fprintf(f,"%s%s@%s",frm,Post->user,Hostname);
if (Post->fullname != NULLCHAR)
fprintf(f," (%s )",Post->fullname);
fputc('\n',f);
tputs("Newsgroup? ");
recvline(sp->input,buf,LineLen);
rip2(buf);
if (check_blank(buf))
goto done;
fprintf(f,"%s%s\n",ngrps,buf);
tputs("Subject? ");
recvline(sp->input,buf,LineLen);
fprintf(f,"%s%s",subj,buf);
fprintf(f,"%s<%ld@%s>\n",msgid,id,Hostname);
time(&currtime);
fprintf(f,"Date: %s",ptime(&currtime));
fprintf(f,"Sender: NNTP@%s\n",Hostname);
if (Post->reply != NULLCHAR)
fprintf(f,"%s%s\n",replyto,Post->reply);
if (Post->organ != NULLCHAR)
fprintf(f,"Organization: %s\n",Post->organ);
fputc('\n',f);
tputs("Enter message - end with .\n");
for (;;) {
recvline(sp->input,buf,LineLen);
if(strcmp(buf,".u\n") == 0
|| strcmp(buf,".r\n") == 0) {
tputs("Filename? ");
recvline(sp->input,buf,LineLen);
rip2(buf);
if((ufp = open_file(buf,READ_TEXT,0,1)) != NULLFILE) {
while(fgets(buf,LineLen,ufp) != NULL)
fputs(buf,f);
fclose(ufp);
}
tputs("(continue)\n");
}
if(strcmp(buf,".\n") == 0
|| strcmpi(buf,"***END\n") == 0
|| strcmpi(buf,"/EX\n") == 0)
break;
fputs(buf,f);
}
if (Post->sig != NULLCHAR) {
sprintf(buf,"%s",Post->sig);
if ((idf = open_file(buf,READ_TEXT,0,1)) != NULLFILE ) {
while(fgets(buf,LineLen,idf) != NULL)
fputs(buf,f);
fclose(idf);
}
}
loop: tputs("\n[Send, Abort, Exit, List] ");
recvline(sp->input,buf,LineLen);
switch(tolower(buf[0])) {
case 's':
rewind(f);
sprintf(mp->buf,"<%ld@%s>",id,Hostname);
mp->id = strdup(mp->buf);
if (xfer_article2(f,mp) < 1)
tputs("\007Posting failed\n");
break;
case 'l':
rewind(f);
for(;;) {
if (fgets(buf,LineLen,f) == NULL)
break;
tputs(buf);
}
rewind(f);
goto loop;
case 'e':
fclose(f);
goto done;
case 'a':
break;
default:
goto loop;
}
fclose(f);
tputs("Post another? ");
recvline(sp->input,buf,LineLen);
if (tolower(buf[0]) == 'n')
goto done;
}
done:
if(f != NULLFILE)
fclose(f);
keywait(NULLCHAR,1);
free((char *) mp);
freesession(sp);
return 0;
}
static int
donnquiet(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setintrc(&Nntpquiet,"NNTP quiet",argc,argv,0,2);
}
/* -------------------- Profile subcmds -------------------- */
static int
donnuser(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2 && Post->user != NULLCHAR)
tprintf("%s\n",Post->user);
else {
free(Post->user);
Post->user = strdup(argv[1]);
}
return 0;
}
static int
donnsig(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2 && Post->sig != NULLCHAR)
tprintf("%s\n",Post->sig);
else {
if(access(argv[1],0) == 0) {
free(Post->sig);
Post->sig = strdup(argv[1]);
} else {
tputs("No such signature file\n");
return -1;
}
}
return 0;
}
static int
donnfull(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2 && Post->fullname != NULLCHAR)
tprintf("%s\n",Post->fullname);
else {
free(Post->fullname);
Post->fullname = strdup(argv[1]);
}
return 0;
}
static int
donnhost(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2 && Host != NULLCHAR)
tprintf("%s\n",Host);
else {
free(Host);
Host = strdup(argv[1]);
}
return 0;
}
static int
donnihave(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setintrc(&NnIhave,"NNTP Ihave",argc,argv,0,2);
}
static int
donnorgan(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2 && Post->organ != NULLCHAR)
tprintf("%s\n",Post->organ);
else {
free(Post->organ);
Post->organ = strdup(argv[1]);
}
return 0;
}
static int
donnread(argc,argv,p)
int argc;
char *argv[];
void *p;
{
FILE *f;
struct session *sp;
struct article *art;
char cp[LineLen], buf[81];
int number, row, Nrows=NROWS, flag = argc;
if((art = (struct article *)mallocw(sizeof(struct article))) == NULLARTICLE)
return -1;
art->group = strdup(argv[1]);
if(get_path2(art) == 1) {
if(argc > 2) {
number = atoi(argv[2]);
} else
number = 1;
sprintf(cp,"%s/news.rc",art->path);
if(flag < 3 && (f = fopen(cp,READ_TEXT)) != NULLFILE) {
if((fgets(buf,sizeof(buf),f)) != 0) {
number = atoi(buf);
number++;
}
fclose(f);
}
if((sp = newsession("NNTP read",MORE,0)) != NULLSESSION) {
for(;;) {
if(number < 1)
number = 1;
sp->ttystate.echo = sp->ttystate.edit = 0;
row = Nrows - 4;
sprintf(cp,"%s/%d",art->path,number);
if((f = fopen(cp,READ_TEXT)) != NULLFILE) {
tprintf("Msg #%d\n",number);
while(fgets(buf,sizeof(buf),f),!feof(f)) {
tputs(buf);
if(--row == 0){
row = keywait("--More--",0);
switch(row){
case -1:
case 'q':
fclose(f);
goto done;
case '\n':
case '\r':
row = 2;
break;
default:
row = Nrows - 3;
}
}
}
fclose(f);
} else {
number--;
tputs("No more news");
}
done:
row = keywait("\nRead next/previous? (n/p/q)",0);
switch(row) {
case -1:
case 'q':
goto done2;
case 'p':
flag = 3;
if(--number < 1)
goto done2;
continue;
default:
number++;
continue;
}
}
done2:
if(flag < 3) {
sprintf(cp,"%s/news.rc",art->path);
if((f = fopen(cp,WRITE_TEXT)) != NULLFILE) {
sprintf(cp,"%d\n",number);
fputs(cp,f);
fclose(f);
}
}
keywait(NULLCHAR,1);
freesession(sp);
}
} else {
tprintf("No such newsgroup %s\n",art->group);
}
free(art->path);
free(art->group);
free(art);
return 0;
}
static int
donnreply(argc,argv,p)
int argc;
char *argv[];
void *p;
{
if(argc < 2 && Post->reply != NULLCHAR)
tprintf("%s\n",Post->reply);
else {
free(Post->reply);
Post->reply = strdup(argv[1]);
}
return 0;
}
/* subcmd parser */
static int
donnprofile(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct cmds Prof[] = {
"fullname", donnfull, 0, 0, NULLCHAR,
"host", donnhost, 0, 0, NULLCHAR,
"organ", donnorgan, 0, 0, NULLCHAR,
"reply", donnreply, 0, 0, NULLCHAR,
"sig", donnsig, 0, 0, NULLCHAR,
"user", donnuser, 0, 0, NULLCHAR,
NULLCHAR,
};
if(Post == NULLPOST) {
Post = (struct post *)callocw(1,sizeof(struct post));
Post->user = Post->reply = Post->sig = Post->organ = Post->fullname = NULLCHAR;
}
if (Host == NULLCHAR) {
Host = strdup(Hostname);
}
return (argc == 10) ? 0 : (subcmd(Prof,argc,argv,p));
}
/* cmd parser */
int
donntp(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct cmds Nntp[] = {
"active", donnactive, 0, 0, NULLCHAR,
"access", donnaccess, 0, 0, NULLCHAR,
"add", donnadds, 0, 3, "nntp add <nntpserv> <interval> [<groups>]",
"create", donncreate, 0, 2, "nntp create <newsgroup> [y|n]",
"drop", donndrops, 0, 2, "nntp drop <nntpserv>",
"dump", donndump, 0, 2, "nntp dump <newsgroup> [<mailbox>]",
"firstpoll", donnfirstpoll, 0, 0, NULLCHAR,
"ihave", donnihave, 0, 0, NULLCHAR,
"kick", donnkick, 0, 2, "nntp kick <server>",
"list", donnlists, 0, 0, NULLCHAR,
#ifdef LZW
"lzw", donnlzw, 0, 0, NULLCHAR,
#endif
"post", donnpost, 2024, 0, NULLCHAR,
"profile", donnprofile, 0, 0, NULLCHAR,
"read", donnread, 1024, 2, "nntp read <newsgroup> [number]",
"quiet", donnquiet, 0, 0, NULLCHAR,
NULLCHAR,
};
return (subcmd(Nntp,argc,argv,p));
}
/* main file-opening routine
* options: s = socketnumber, if given an error msg is printed to the socket
* returncode: NULLFILE if error; filepointer success
*/
FILE *
open_file(name,mode,s,t)
char *name;
char *mode;
int s;
int t;
{
FILE *f;
#ifdef MSDOS
register char *cp;
#endif
if(name == NULLCHAR || mode == NULLCHAR)
return NULLFILE;
#ifdef MSDOS
while((cp = strchr(name,'\\')) != NULLCHAR)
*cp = '/';
#endif
if((f = fopen(name,mode)) == NULLFILE) {
if(s)
usprintf(s,fatal,name);
if(t)
tprintf("Can't open %s: %s\n",name,sys_errlist[errno]);
}
return f;
}
/* main tempfile-opening routine
* returncode: NULLFILE if error; filepointer success
*/
FILE *
temp_file(s,t)
int s;
int t;
{
FILE *f;
if((f = tmpfile()) == NULLFILE) {
if(s)
usprintf(s,fatal,"TMP");
if(t) {
tprintf("Can't open TMP: %s\n",sys_errlist[errno]);
}
}
return f;
}
static void
make_time_string(char *string,time_t *timep)
{
struct tm *stm;
stm = localtime(timep);
sprintf(string,"%02d%02d%02d %02d%02d%02d",
stm->tm_year%100,stm->tm_mon + 1,stm->tm_mday,stm->tm_hour,
stm->tm_min,stm->tm_sec);
}
#endif /* NNTPS */