This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
deb-mbse/mbfido/scannews.c

1438 lines
38 KiB
C
Raw Normal View History

2001-08-17 05:46:24 +00:00
/*****************************************************************************
*
* File ..................: mbfido/scannews.c
* Purpose ...............: Scan for new News
* Last modification date : 01-Jul-2001
*
*****************************************************************************
* Copyright (C) 1997-2001
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* MBSE BBS 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.
*
* You should have received a copy of the GNU General Public License
* along with MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../lib/libs.h"
#include "../lib/structs.h"
#include "../lib/records.h"
#include "../lib/common.h"
#include "../lib/clcomm.h"
#include "../lib/mbinet.h"
#include "../lib/dbdupe.h"
#include "../lib/dbnode.h"
#include "../lib/dbmsgs.h"
#include "../lib/msg.h"
#include "../lib/msgtext.h"
#include "mkftnhdr.h"
#include "hash.h"
#include "echoout.h"
#include "rollover.h"
#include "pack.h"
#include "scannews.h"
#define MAXHDRSIZE 2048
#define MAXSEEN 70
#define MAXPATH 73
/*
* Global variables
*/
POverview xoverview = NULL;
int marker = 0;
static int ftnorigin;
static int removemime;
static int removemsgid;
static int removeref;
static int removeinreply;
static int removesupersedes;
static int removeapproved;
static int removereplyto;
static int removereturnto;
static int dirtyoutcode = CHRS_NOTSET;
/*
* External variables
*/
extern int do_quiet;
extern int do_learn;
extern int most_debug;
extern int news_in;
extern int news_imp;
extern int news_dupe;
extern int echo_out;
extern int echo_in;
extern char *replyaddr;
extern char *toname; /* To user */
extern char *fromname; /* From user */
extern char *subj; /* Message subject */
/*
* Internal functions
*/
int do_one_group(List **, char *, char *);
int get_xover(char *, long, long, List **);
int get_xoverview(void);
void tidy_artlist(List **);
void fill_artlist(List **, char *, long, int);
void Marker(void);
int get_article(char *, char *);
int needputrfc(rfcmsg *);
void tidy_artlist(List **fdp)
{
List *tmp, *old;
for (tmp = *fdp; tmp; tmp = old) {
old = tmp->next;
free(tmp);
}
*fdp = NULL;
}
/*
* Add article to the list
*/
void fill_artlist(List **fdp, char *id, long nr, int dupe)
{
List **tmp;
Syslog('N', "Fill %s %ld %s", id, nr, dupe ? "Dupe":"New msg");
for (tmp = fdp; *tmp; tmp = &((*tmp)->next));
*tmp = (List *)malloc(sizeof(List));
(*tmp)->next = NULL;
sprintf((*tmp)->msgid, "%s", id);
(*tmp)->nr = nr;
(*tmp)->isdupe = dupe;
}
/*
* write an arbitrary line to message body,
* if a line starts with three dashes, insert a dash and a blank
*/
int charwrite(char *, FILE *);
int charwrite(char *s, FILE *fp)
{
if ((strlen(s) >= 3) && (strncmp(s,"---",3) == 0) && (s[3] != '-')) {
putc('-',fp);
putc(' ',fp);
}
while (*s) {
putc(*s, fp);
s++;
}
return 0;
}
/*
* write (multiline) header to kluge: change \n to ' ' and end line with \n
*/
int kludgewrite(char *, FILE *);
int kludgewrite(char *s, FILE *fp)
{
while (*s) {
if (*s == '\r')
putc('\n', fp);
else {
if (*s != '\n')
putc(*s, fp);
else if (*(s+1))
putc(' ',fp);
}
s++;
}
putc('\n',fp);
return 0;
}
void Marker(void)
{
if (do_quiet)
return;
switch (marker) {
case 0: printf(">---");
break;
case 1: printf(">>--");
break;
case 2: printf(">>>-");
break;
case 3: printf(">>>>");
break;
case 4: printf("<>>>");
break;
case 5: printf("<<>>");
break;
case 6: printf("<<<>");
break;
case 7: printf("<<<<");
break;
case 8: printf("-<<<");
break;
case 9: printf("--<<");
break;
case 10:printf("---<");
break;
case 11:printf("----");
break;
}
printf("\b\b\b\b");
fflush(stdout);
if (marker < 11)
marker++;
else
marker = 0;
}
/*
* Scan for new news available at the nntp server.
*/
void ScanNews(void)
{
List *art = NULL;
POverview tmp, old;
FILE *pAreas;
char *sAreas;
struct msgareashdr Msgshdr;
struct msgareas Msgs;
IsDoing((char *)"Scan News");
if (nntp_connect() == -1) {
WriteError("Can't connect to newsserver");
return;
}
if (get_xoverview())
return;
if (!do_quiet) {
colour(10, 0);
printf("Scan for new news articles\n");
}
sAreas = calloc(PATH_MAX, sizeof(char));
sprintf(sAreas, "%s/etc/mareas.data", getenv("MBSE_ROOT"));
if(( pAreas = fopen (sAreas, "r")) == NULL) {
WriteError("$Can't open Messages Areas File.");
return;
}
fread(&Msgshdr, sizeof(Msgshdr), 1, pAreas);
while (fread(&Msgs, Msgshdr.recsize, 1, pAreas) == 1) {
fseek(pAreas, Msgshdr.syssize, SEEK_CUR);
if ((Msgs.Active) && strlen(Msgs.Newsgroup)) {
if (IsSema((char *)"upsalarm")) {
Syslog('+', "Detected upsalarm semafore, aborting newsscan");
break;
}
Syslog('n', "Scan newsgroup: %s", Msgs.Newsgroup);
if (!do_quiet) {
colour(3, 0);
printf("\r%-40s", Msgs.Newsgroup);
fflush(stdout);
}
Nopper();
if (do_one_group(&art, Msgs.Newsgroup, Msgs.Tag) == RETVAL_ERROR)
break;
}
}
fclose(pAreas);
free(sAreas);
for (tmp = xoverview; tmp; tmp = old) {
old = tmp->next;
if (tmp->header)
free(tmp->header);
if (tmp->field)
free(tmp->field);
free(tmp);
}
packmail();
if (!do_quiet)
printf("\r \r");
}
int do_one_group(List **art, char *grpname, char *ftntag)
{
List *tmp;
char temp[128], *resp;
int retval;
long total, start, end;
Syslog('N', "do_one_group(%s, %s)", grpname, ftntag);
IsDoing((char *)"Scan %s", grpname);
sprintf(temp, "GROUP %s\r\n", grpname);
nntp_send(temp);
resp = nntp_receive();
retval = atoi(strtok(resp, " "));
if (retval != 211) {
if (retval == 411)
WriteError("No such newsgroup: %s", grpname);
else
WriteError("Unknown response %d to GROUP command", retval);
return RETVAL_ERROR;
}
total = atol(strtok(NULL, " "));
start = atol(strtok(NULL, " "));
end = atol(strtok(NULL, " '\0'"));
if (!total) {
Syslog('N', "No articles");
return RETVAL_OK;
}
retval = get_xover(grpname, start, end, art);
if (retval != RETVAL_OK) {
tidy_artlist(art);
return retval;
}
if (!do_learn) {
for (tmp = *art; tmp; tmp = tmp->next) {
if (!tmp->isdupe) {
/*
* If the message isn't a dupe, it must be new for us.
*/
most_debug = TRUE;
get_article(tmp->msgid, ftntag);
most_debug = FALSE;
}
}
}
tidy_artlist(art);
return RETVAL_OK;
}
int get_article(char *msgid, char *ftntag)
{
char cmd[81], *resp;
int retval, done = FALSE;
FILE *fp = NULL;
Syslog('n', "Get article %s, %s", msgid, ftntag);
if (!SearchMsgs(ftntag)) {
WriteError("Search message area %s failed", ftntag);
return RETVAL_ERROR;
}
IsDoing("Article %d", (news_in + 1));
sprintf(cmd, "ARTICLE %s\r\n", msgid);
nntp_send(cmd);
resp = nntp_receive();
retval = atoi(strtok(resp, " "));
switch (retval) {
case 412: WriteError("No newsgroup selected");
return RETVAL_UNEXPECTEDANS;
case 420: WriteError("No current article has been selected");
return RETVAL_UNEXPECTEDANS;
case 423: WriteError("No such article in this group");
return RETVAL_UNEXPECTEDANS;
case 430: WriteError("No such article found");
return RETVAL_UNEXPECTEDANS;
case 220: if ((fp = tmpfile()) == NULL) {
WriteError("$Can't open tmpfile");
return RETVAL_UNEXPECTEDANS;
}
while (done == FALSE) {
resp = nntp_receive();
if ((strlen(resp) == 1) && (strcmp(resp, ".") == 0)) {
done = TRUE;
} else {
fwrite(resp, strlen(resp), 1, fp);
fputc('\n', fp);
}
}
break;
}
news_in++;
IsDoing("Article %d", (news_in));
retval = do_article(fp);
fclose(fp);
return retval;
}
int do_article(FILE *fp)
{
char sbe[16], *p, *q, *temp;
int i, incode, outcode, pgpsigned;
int First = TRUE, seenlen, oldnet;
sysconnect Link;
rfcmsg *msg = NULL, *tmsg, *tmp;
ftnmsg *fmsg = NULL;
FILE *ofp;
fa_list *sbl = NULL, *ptl = NULL, *tmpl;
faddr *ta, *From;
unsigned long svmsgid, svreply;
int sot_kludge = FALSE, eot_kludge = FALSE, qp_or_base64 = FALSE, tinyorigin = FALSE;
int needsplit, hdrsize, datasize, splitpart, forbidsplit, rfcheaders;
char newsubj[4 * (MAXSUBJ+1)], *oldsubj, *acup_a = NULL;
unsigned long acup_n = 0, crc2;
int html_message = FALSE;
time_t Now;
rewind(fp);
msg = parsrfc(fp);
incode = outcode = CHRS_NOTSET;
pgpsigned = FALSE;
p = hdr((char *)"Content-Type",msg);
if (p)
incode=readcharset(p);
if (incode == CHRS_NOTSET) {
p = hdr((char *)"X-FTN-CHRS",msg);
if (p == NULL)
p = hdr((char *)"X-FTN-CHARSET", msg);
if (p == NULL)
p = hdr((char *)"X-FTN-CODEPAGE", msg);
if (p)
incode = readchrs(p);
}
if ((p = hdr((char *)"Content-Type",msg)) && ((strcasestr(p,(char *)"multipart/signed")) ||
(strcasestr(p,(char *)"application/pgp")))) {
pgpsigned = TRUE;
outcode = incode;
} else if ((p = hdr((char *)"X-FTN-ORIGCHRS", msg)))
outcode = readchrs(p);
else if (dirtyoutcode != CHRS_NOTSET)
outcode = dirtyoutcode;
else
outcode = getoutcode(incode);
for (tmsg = msg; tmsg; tmsg = tmsg->next)
if (strcasecmp(tmsg->key, "X-FTN-SEEN-BY") == 0)
fill_list(&sbl, tmsg->val, NULL, TRUE);
if (!CFG.allowcontrol) {
if (hdr((char *)"Control",msg)) {
Syslog('n', "skipping news message");
tidy_falist(&sbl);
tidyrfc(msg);
return RETVAL_OK;
}
}
if ((fmsg = mkftnhdr(msg, incode, outcode, TRUE)) == NULL) {
WriteError("Unable to create FTN headers from RFC ones, aborting");
tidy_falist(&sbl);
tidyrfc(msg);
return RETVAL_ERROR;
}
/*
* Setup PATH line
*/
sprintf(sbe, "%u/%u", msgs.Aka.net, msgs.Aka.node);
fill_path(&ptl, sbe);
fmsg->area = xstrcpy(msgs.Tag);
svmsgid = fmsg->msgid_n;
svreply = fmsg->reply_n;
if ((p = hdr((char *)"Message-ID",msg))) {
ftnmsgid(p, &fmsg->msgid_a, &fmsg->msgid_n, fmsg->area);
hash_update_s(&fmsg->msgid_n, fmsg->area);
}
if ((p = hdr((char *)"References",msg))) {
p = strrchr(p,' ');
ftnmsgid(p,&fmsg->reply_a, &fmsg->reply_n,fmsg->area);
if (!chkftnmsgid(p)) {
hash_update_s(&fmsg->reply_n, fmsg->area);
}
} else if ((p = hdr((char *)"In-Reply-To",msg))) {
ftnmsgid(p,&fmsg->reply_a, &fmsg->reply_n,fmsg->area);
if (!chkftnmsgid(p)) {
hash_update_s(&fmsg->reply_n, fmsg->area);
}
}
if (incode == CHRS_NOTSET)
incode = msgs.Rfccode;
if (outcode == CHRS_NOTSET)
outcode = msgs.Ftncode;
if ((incode == CHRS_NOTSET) && (hdr((char *)"Message-ID",msg))) {
if (chkftnmsgid(hdr((char *)"Message-ID",msg)))
incode = CHRS_DEFAULT_FTN;
else
incode = CHRS_DEFAULT_RFC;
}
temp = calloc(4096, sizeof(char));
removemime = FALSE;
removemsgid = FALSE;
removeref = FALSE;
removeinreply = FALSE;
removesupersedes = FALSE;
removeapproved = FALSE;
removereplyto = TRUE;
removereturnto = TRUE;
ftnorigin = fmsg->ftnorigin;
if ((hdr((char *)"X-PGP-Signed",msg)))
pgpsigned = TRUE;
if (pgpsigned)
Syslog('n', "pgpsigned = %s", pgpsigned ? "True":"False");
q = hdr((char *)"Content-Transfer-Encoding",msg);
if (q)
while (*q && isspace(*q))
q++;
if (!(q))
q = (char *)"8bit";
if ((p = hdr((char *)"Content-Type",msg))) {
while (*p && isspace(*p))
p++;
/*
* turn the quoted-printable decode mode on; remember FTN is virtually 8-bit clean
*/
if ((strncasecmp(p, "text/plain", 10) == 0) && (strncasecmp(q, "quoted-printable", 16) == 0))
qp_or_base64 = 1;
/*
* turn the base64 decode mode on
*/
else if ((strncasecmp(p, "text/plain", 10) == 0) && (strncasecmp(q, "base64", 6) == 0))
qp_or_base64 = 2;
/*
* text/html support from FSC-HTML 001 proposal of Odinn Sorensen (2:236/77)
*/
if (strncasecmp(p, "text/html", 9) == 0)
html_message = TRUE;
for (tmp = msg; tmp; tmp = tmp->next)
if (((strcasecmp(tmp->key,"X-FTN-KLUDGE") == 0) && (strcasecmp(tmp->val,"FSCHTML") == 0)) ||
(strcasecmp(tmp->key,"X-FTN-HTML") == 0))
html_message = FALSE;
if ((readcharset(p) != CHRS_NOTSET ) && ((q == NULL) || (strncasecmp(q,"7bit",4) == 0) ||
((!pgpsigned) && (qp_or_base64==1)) || ((!pgpsigned) && (qp_or_base64==2)) || (strncasecmp(q,"8bit",4) == 0)))
removemime=1; /* no need in MIME headers */
/*
* some old MUA puts "text" instead of "text/plain; charset=..."
*/
else if ((strcasecmp(p,"text\n") == 0))
removemime = TRUE;
}
if (removemime || qp_or_base64 || html_message)
Syslog('n', "removemime=%s, qp_or_base64 = %d, html_message=%s", removemime ? "True":"False", qp_or_base64,
html_message ? "True":"False");
if ((p = hdr((char *)"Message-ID",msg))) {
if (!removemsgid)
removemsgid = chkftnmsgid(p);
}
Syslog('n', "removemsgid = %s", removemsgid ? "True":"False");
if ((!removeref) && (p = hdr((char *)"References",msg))) {
p = xstrcpy(p);
q = strtok(p," \t\n");
if ((q) && (strtok(NULL," \t\n") == NULL))
removeref = chkftnmsgid(q);
free(p);
}
if (removeref)
Syslog('n', "removeref = %s", removeref ? "True":"False");
if ((p = hdr((char *)"Supersedes",msg)))
removesupersedes = chkftnmsgid(p);
if (removesupersedes)
Syslog('n', "removesupersedes = %s", removesupersedes ? "True":"False");
if ((p = hdr((char *)"Approved",msg))) {
while (*p && isspace(*p))
p++;
if ((q = strchr(p,'\n')))
*q='\0';
if (strlen(msgs.Moderator) && (strcasestr(msgs.Moderator,p)))
removeapproved = TRUE;
if (q)
*q='\n';
}
if (removeapproved)
Syslog('n', "removeapproved = %s", removeapproved ? "True":"False");
if ((p = hdr((char *)"Reply-To",msg))) {
removereplyto = FALSE;
if ((q = hdr((char *)"From",msg))) {
char *r;
r = xstrcpy(p);
p = r;
while(*p && isspace(*p))
p++;
if (p[strlen(p)-1] == '\n')
p[strlen(p)-1]='\0';
if (strcasestr(q,p))
removereplyto = TRUE;
free(r);
}
}
Syslog('n', "removereplyto = %s", removereplyto ? "True":"False");
if ((p = hdr((char *)"Return-Receipt-To",msg))) {
removereturnto = FALSE;
if ((q = hdr((char *)"From",msg))) {
char *r;
r = xstrcpy(p);
p = r;
while (*p && isspace(*p))
p++;
if (p[strlen(p)-1] == '\n')
p[strlen(p)-1]='\0';
if (strcasestr(q,p))
removereturnto = TRUE;
// free(r);
}
}
if (!removereturnto)
Syslog('n', "removereturnto = %s", removereturnto ? "True":"False");
p = ascfnode(fmsg->from,0x1f);
i = 79-11-3-strlen(p);
if (ftnorigin && fmsg->origin && (strlen(fmsg->origin) > i)) {
/* This is a kludge... I don't like it too much. But well,
if this is a message of FTN origin, the original origin (:)
line MUST have been short enough to fit in 79 chars...
So we give it a try. Probably it would be better to keep
the information about the address format from the origin
line in a special X-FTN-... header, but this seems even
less elegant. Any _good_ ideas, anyone? */
/* OK, I am keeping this, though if should never be used
al long as X-FTN-Origin is used now */
p = ascfnode(fmsg->from,0x0f);
Syslog('n', "checkorigin 3");
i = 79-11-3-strlen(p);
tinyorigin = TRUE;
}
if (tinyorigin)
Syslog('n', "tinyorigin = %s", tinyorigin ? "True":"False");
if ((fmsg->origin) && (strlen(fmsg->origin) > i))
fmsg->origin[i]='\0';
forbidsplit = (ftnorigin || (hdr((char *)"X-FTN-Split",msg)));
needsplit = 0;
splitpart = 0;
hdrsize = 20;
hdrsize += (fmsg->subj)?strlen(fmsg->subj):0;
if (fmsg->from)
hdrsize += (fmsg->from->name)?strlen(fmsg->from->name):0;
if (fmsg->to)
hdrsize += (fmsg->to->name)?strlen(fmsg->to->name):0;
do {
Syslog('n', "split loop, splitpart = %d", splitpart);
datasize = 0;
if (splitpart) {
sprintf(newsubj,"[part %d] ",splitpart+1);
strncat(newsubj,fmsg->subj,MAXSUBJ-strlen(newsubj));
} else {
strncpy(newsubj,fmsg->subj,MAXSUBJ);
}
strcpy(newsubj, hdrnconv(newsubj, incode, outcode, MAXSUBJ));
newsubj[MAXSUBJ]='\0';
if (splitpart) {
hash_update_n(&fmsg->msgid_n,splitpart);
}
oldsubj = fmsg->subj;
fmsg->subj = newsubj;
/*
* Create a new temp message in FTN style format
*/
if ((ofp = tmpfile()) == NULL) {
WriteError("$Can't open second tmpfile");
tidy_falist(&sbl);
tidy_falist(&ptl);
tidyrfc(msg);
return RETVAL_ERROR;
}
fprintf(ofp, "AREA:%s\n", msgs.Tag);
fprintf(ofp, "\001MSGID: %s %08lx\n", MBSE_SS(fmsg->msgid_a),fmsg->msgid_n);
if (fmsg->reply_s)
fprintf(ofp, "\1REPLY: %s\n", fmsg->reply_s);
else if (fmsg->reply_a)
fprintf(ofp, "\1REPLY: %s %08lx\n", fmsg->reply_a, fmsg->reply_n);
Now = time(NULL) - (gmt_offset((time_t)0) * 60);
fprintf(ofp, "\001TZUTC: %s\n", gmtoffset(Now));
fmsg->subj = oldsubj;
if ((p = hdr((char *)"X-FTN-REPLYADDR",msg))) {
Syslog('n', "replyaddr 1 %s", p);
hdrsize += 10+strlen(p);
fprintf(ofp,"\1REPLYADDR:");
kludgewrite(p,ofp);
} else if (replyaddr) {
Syslog('n', "replyaddr 2");
hdrsize += 10+strlen(replyaddr);
fprintf(ofp,"\1REPLYADDR: ");
kludgewrite(replyaddr,ofp);
}
if ((p = hdr((char *)"X-FTN-REPLYTO",msg))) {
hdrsize += 8+strlen(p);
fprintf(ofp,"\1REPLYTO:");
kludgewrite(p,ofp);
} else if (replyaddr) {
hdrsize += 15;
fprintf(ofp,"\1REPLYTO: %s UUCP\n", aka2str(msgs.Aka));
} else if ((p = hdr((char *)"Reply-To",msg))) {
if ((ta = parsefaddr(p))) {
if ((q = hdr((char *)"From",msg))) {
if (!strcasestr(q,p)) {
fprintf(ofp,"\1REPLYTO: %s %s\n", ascfnode(ta,0x1f), ta->name);
}
tidy_faddr(ta);
}
}
}
if ((p=strip_flags(hdr((char *)"X-FTN-FLAGS",msg)))) {
hdrsize += 15;
fprintf(ofp,"\1FLAGS:%s\n",p);
free(p);
}
if (!hdr((char *)"X-FTN-PID", msg)) {
p = hdr((char *)"User-Agent", msg);
if (p == NULL)
p = hdr((char *)"X-Newsreader", msg);
if (p == NULL)
p = hdr((char *)"X-Mailer", msg);
if (p) {
hdrsize += 4 + strlen(p);
fprintf(ofp, "\1PID:");
kludgewrite(p, ofp);
} else {
fprintf(ofp, "\001PID: MBSE-FIDO %s\n", VERSION);
}
}
hdrsize += 8 + strlen(getchrs(outcode));
fprintf(ofp, "\001CHRS: %s\n", getchrs(outcode));
if (html_message) {
hdrsize += 9;
fprintf(ofp, "\1HTML: 5\n");
}
if (CFG.allowcontrol && (!hdr((char *)"X-FTN-ACUPDATE",msg)) && (p=hdr((char *)"Control",msg))) {
if (strstr(p,"cancel")) {
ftnmsgid(p,&acup_a,&acup_n,fmsg->area);
if (acup_a) {
hash_update_s(&acup_n,fmsg->area);
hdrsize += 26 + strlen(acup_a);
fprintf(ofp,"\1ACUPDATE: DELETE %s %08lx\n", acup_a,acup_n);
}
}
}
if ((!hdr((char *)"X-FTN-ACUPDATE",msg)) && (p=hdr((char *)"Supersedes",msg))) {
ftnmsgid(p,&acup_a,&acup_n,fmsg->area);
if (acup_a) {
hash_update_s(&acup_n,fmsg->area);
hdrsize += 26 + strlen(acup_a);
fprintf(ofp,"\1ACUPDATE: MODIFY %s %08lx\n", acup_a,acup_n);
}
}
#ifdef FSC_0070
/* FSC-0070 */
if((p = hdr((char *)"Message-ID", msg)) && !(hdr((char *)"X-FTN-RFCID", msg))) {
q = strdup(p);
fprintf(ofp,"\1RFCID:");
if ((l = strrchr(q, '<')) && (r = strchr(q, '>')) && (l < r)) {
*l++ = ' ';
while(*l && isspace(*l))
l++;
l--; /* leading ' ' */
*r-- = '\0';
while(*r && isspace(*r))
*r-- = '\0';
} else
l = q;
kludgewrite(l, ofp);
hdrsize += 6 + strlen(l);
free(q);
}
#endif /* FSC_0070 */
if (!(hdr((char *)"X-FTN-Tearline", msg)) && !(hdr((char *)"X-FTN-TID", msg))) {
sprintf(temp, " MBSE-FIDO %s", VERSION);
hdrsize += 4 + strlen(temp);
fprintf(ofp, "\1TID:");
kludgewrite(temp, ofp);
}
if ((splitpart == 0) || (hdrsize < MAXHDRSIZE)) {
for (tmp = msg; tmp; tmp = tmp->next) {
if ((!strncmp(tmp->key,"X-Fsc-",6)) ||
(!strncmp(tmp->key,"X-FTN-",6) &&
strcasecmp(tmp->key,"X-FTN-Tearline") &&
strcasecmp(tmp->key,"X-FTN-Origin") &&
strcasecmp(tmp->key,"X-FTN-Sender") &&
strcasecmp(tmp->key,"X-FTN-Split") &&
strcasecmp(tmp->key,"X-FTN-FLAGS") &&
strcasecmp(tmp->key,"X-FTN-AREA") &&
strcasecmp(tmp->key,"X-FTN-MSGID") &&
strcasecmp(tmp->key,"X-FTN-REPLY") &&
strcasecmp(tmp->key,"X-FTN-SEEN-BY") &&
strcasecmp(tmp->key,"X-FTN-PATH") &&
strcasecmp(tmp->key,"X-FTN-REPLYADDR") &&
strcasecmp(tmp->key,"X-FTN-REPLYTO") &&
strcasecmp(tmp->key,"X-FTN-To") &&
strcasecmp(tmp->key,"X-FTN-From") &&
strcasecmp(tmp->key,"X-FTN-CHARSET") &&
strcasecmp(tmp->key,"X-FTN-CHRS") &&
strcasecmp(tmp->key,"X-FTN-CODEPAGE") &&
strcasecmp(tmp->key,"X-FTN-ORIGCHRS") &&
strcasecmp(tmp->key,"X-FTN-SOT") &&
strcasecmp(tmp->key,"X-FTN-EOT") &&
strcasecmp(tmp->key,"X-FTN-Via"))) {
if ((strcasecmp(tmp->key,"X-FTN-KLUDGE") == 0)) {
if (!strcasecmp(tmp->val," SOT:\n"))
sot_kludge = TRUE;
else if (!strcasecmp(tmp->val," EOT:\n"))
eot_kludge = TRUE;
else {
hdrsize += strlen(tmp->val);
fprintf(ofp,"\1");
/* we should have restored the original string here... */
kludgewrite((tmp->val)+1,ofp);
}
} else {
hdrsize += strlen(tmp->key)+strlen(tmp->val);
fprintf(ofp,"\1%s:",tmp->key+6);
kludgewrite(tmp->val,ofp);
}
}
}
/* ZConnect are X-ZC-*: in usenet, \1ZC-*: in FTN */
for (tmp=msg;tmp;tmp=tmp->next)
if ((!strncmp(tmp->key,"X-ZC-",5))) {
hdrsize += strlen(tmp->key)+strlen(tmp->val);
fprintf(ofp,"\1%s:",tmp->key+2);
kludgewrite(tmp->val,ofp);
}
/* mondo.org gateway uses ".MSGID: ..." in usenet */
for (tmp=msg;tmp;tmp=tmp->next)
if ((!strncmp(tmp->key,".",1)) && (strcasecmp(tmp->key,".MSGID"))) {
hdrsize += strlen(tmp->key)+strlen(tmp->val);
fprintf(ofp,"\1%s:",tmp->key+1);
kludgewrite(tmp->val,ofp);
}
rfcheaders=0;
for (tmp = msg; tmp; tmp = tmp->next) {
if ((needputrfc(tmp) == 1)) {
if (strcasestr((char *)"X-Origin-Newsgroups",tmp->key)) {
hdrsize += 10+strlen(tmp->val);
fprintf(ofp,"\1RFC-Newsgroups:");
} else {
hdrsize += strlen(tmp->key)+strlen(tmp->val);
fprintf(ofp,"\1RFC-%s:",tmp->key);
}
kludgewrite(hdrconv(tmp->val, incode, outcode),ofp);
}
}
for (tmp=msg;tmp;tmp=tmp->next) {
if ((needputrfc(tmp) > 1)) {
rfcheaders++;
if (strcasestr((char *)"X-Origin-Newsgroups",tmp->key)) {
hdrsize += 10+strlen(tmp->val);
fprintf(ofp,"Newsgroups:");
} else {
hdrsize += strlen(tmp->key)+strlen(tmp->val);
fprintf(ofp,"%s:",tmp->key);
}
charwrite(hdrconv(tmp->val, incode, outcode),ofp);
}
}
if (rfcheaders)
charwrite((char *)"\n",ofp);
if ((hdr((char *)"X-FTN-SOT",msg)) || (sot_kludge))
fprintf(ofp,"\1SOT:\n");
if ((splitpart == 0) && (hdr((char *)"X-PGP-Signed",msg)))
fprintf(ofp,PGP_SIGNED_BEGIN"\n");
}
if (replyaddr) {
// free(replyaddr); /* Gives SIGSEGV */
replyaddr = NULL;
}
if (needsplit) {
fprintf(ofp," * Continuation %d of a split message *\n\n", splitpart);
needsplit = FALSE;
} else if ((p=hdr((char *)"X-Body-Start",msg))) {
datasize += strlen(p);
if (qp_or_base64==1)
charwrite(strkconv(qp_decode(p), incode, outcode), ofp);
else if (qp_or_base64==2)
charwrite(strkconv(b64_decode(p), incode, outcode), ofp);
else
charwrite(strkconv(p, incode, outcode), ofp);
}
while (!(needsplit=(!forbidsplit) && (((splitpart && (datasize > (CFG.new_split * 1024))) ||
(!splitpart && ((datasize+hdrsize) > (CFG.new_split * 1024)))))) && (bgets(temp,4096-1,fp))) {
datasize += strlen(temp);
if (qp_or_base64==1)
charwrite(strkconv(qp_decode(temp), incode, outcode), ofp);
else if (qp_or_base64==2)
charwrite(strkconv(b64_decode(temp), incode, outcode), ofp);
else
charwrite(strkconv(temp, incode, outcode), ofp);
}
if (needsplit) {
fprintf(ofp,"\n * Message split, to be continued *\n");
splitpart++;
} else if ((p=hdr((char *)"X-PGP-Signed",msg))) {
fprintf(ofp,PGP_SIG_BEGIN"\n");
if ((q=hdr((char *)"X-PGP-Version",msg))) {
fprintf(ofp,"Version:");
charwrite(q,ofp);
}
if ((q=hdr((char *)"X-PGP-Charset",msg))) {
fprintf(ofp,"Charset:");
charwrite(q,ofp);
}
if ((q=hdr((char *)"X-PGP-Comment",msg))) {
fprintf(ofp,"Comment:");
charwrite(q,ofp);
}
fprintf(ofp,"\n");
p=xstrcpy(p);
q=strtok(p," \t\n");
fprintf(ofp,"%s\n",q);
while ((q=(strtok(NULL," \t\n"))))
fprintf(ofp,"%s\n",q);
fprintf(ofp,PGP_SIG_END"\n");
}
if ((p=hdr((char *)"X-FTN-EOT",msg)) || (eot_kludge))
fprintf(ofp,"\1EOT:\n");
if ((p=hdr((char *)"X-FTN-Tearline",msg))) {
fprintf(ofp,"---");
if (strcasecmp(p," (none)\n") == 0)
charwrite((char *)"\n",ofp);
else
charwrite(p,ofp);
} else
fprintf(ofp,"--- MBSE BBSv.%s\n",VERSION);
if ((p = hdr((char *)"X-FTN-Origin",msg))) {
if (*(q=p+strlen(p)-1) == '\n')
*q='\0';
fprintf(ofp," * Origin:");
charwrite(hdrconv(p, incode, outcode),ofp);
} else {
fprintf(ofp," * Origin: "); /* strlen=11 */
if (fmsg->origin)
charwrite(hdrconv(fmsg->origin, incode, outcode), ofp);
else
charwrite(CFG.origin, ofp);
fprintf(ofp," (%s)",
ascfnode(fmsg->from,tinyorigin?0x0f:0x1f));
}
/*
* Setup SEEN-BY lines
*/
for (i = 0; i < 40; i++) {
if (CFG.akavalid[i] && (msgs.Aka.zone == CFG.aka[i].zone) &&
!((msgs.Aka.net == CFG.aka[i].net) && (msgs.Aka.node == CFG.aka[i].node))) {
sprintf(sbe, "%u/%u", CFG.aka[i].net, CFG.aka[i].node);
fill_list(&sbl, sbe, NULL, FALSE);
}
}
sprintf(sbe, "%u/%u", msgs.Aka.net, msgs.Aka.node);
First = TRUE;
/*
* Count downlinks, if there are none then no more SEEN-BY entries will be added.
*/
i = 0;
while (GetMsgSystem(&Link, First)) {
First = FALSE;
if ((Link.aka.zone) && (Link.sendto) && (!Link.pause) && (!Link.cutoff)) {
sprintf(sbe, "%u/%u", Link.aka.net, Link.aka.node);
fill_list(&sbl, sbe, NULL, FALSE);
i++;
}
}
uniq_list(&sbl);
sort_list(&sbl);
seenlen=MAXSEEN+1;
if (i) {
/* ensure it will not match for the first entry */
oldnet = sbl->addr->net-1;
for (tmpl = sbl; tmpl; tmpl = tmpl->next) {
if (tmpl->addr->net == oldnet)
sprintf(sbe," %u",tmpl->addr->node);
else
sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node);
oldnet = tmpl->addr->net;
seenlen += strlen(sbe);
if (seenlen > MAXSEEN) {
seenlen = 0;
fprintf(ofp,"\nSEEN-BY:");
sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node);
seenlen = strlen(sbe);
}
fprintf(ofp,"%s",sbe);
}
} else {
fprintf(ofp,"\nSEEN-BY: %s",sbe);
}
for (tmp = msg; tmp; tmp = tmp->next) {
if (!strcasecmp(tmp->key,"X-FTN-PATH")) {
fill_path(&ptl,tmp->val);
}
}
sprintf(sbe,"%u/%u",msgs.Aka.net, msgs.Aka.node);
fill_path(&ptl,sbe);
uniq_list(&ptl);
seenlen = MAXPATH+1;
/* ensure it will not match for the first entry */
oldnet = ptl->addr->net-1;
for (tmpl = ptl; tmpl; tmpl = tmpl->next) {
if (tmpl->addr->net == oldnet)
sprintf(sbe," %u",tmpl->addr->node);
else
sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node);
oldnet = tmpl->addr->net;
seenlen += strlen(sbe);
if (seenlen > MAXPATH) {
seenlen = 0;
fprintf(ofp,"\n\1PATH:");
sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node);
seenlen = strlen(sbe);
}
fprintf(ofp,"%s",sbe);
}
fprintf(ofp,"\n");
tidy_falist(&ptl);
fflush(ofp);
rewind(ofp);
Syslog('n', "========== Fido start");
while (fgets(temp, 4096, ofp) != NULL) {
/*
* Only log kludges, skip the body
*/
if ((temp[0] == '\001') || !strncmp(temp, "AREA:", 5) || !strncmp(temp, "SEEN-BY", 7)) {
Striplf(temp);
Syslogp('n', printable(temp, 0));
}
}
Syslog('n', "========== Fido end");
rewind(ofp);
Msg_New();
if ((fmsg->to != NULL) && (fmsg->to->name != NULL))
strcpy(Msg.To, fmsg->to->name);
else
sprintf(Msg.To, "All");
Syslog('n', "Msg.To: %s", printable(Msg.To, 0));
toname = xstrcpy(Msg.To);
if ((fmsg->from != NULL) && (fmsg->from->name != NULL)) {
strcpy(Msg.From, fmsg->from->name);
Syslog('n', "Msg.From: %s", printable(Msg.From, 0));
fromname = xstrcpy(Msg.From);
} else {
Syslog('n', "Warning: no Msg.From name found");
}
strcpy(Msg.Subject, fmsg->subj);
subj = xstrcpy(Msg.Subject);
Msg.Echomail = TRUE;
Msg.Written = fmsg->date;
Msg.Arrived = time(NULL) - (gmt_offset((time_t)0) * 60);
sprintf(Msg.FromAddress, "%s", aka2str(msgs.Aka));
/*
* These are the only usefull flags in echomail
*/
if ((fmsg->flags & M_PVT) && ((msgs.MsgKinds == BOTH) || (msgs.MsgKinds == PRIVATE)))
Msg.Private = TRUE;
if (fmsg->flags & M_FILE)
Msg.FileAttach = TRUE;
/*
* Set MSGID and REPLYID crc.
*/
if (fmsg->msgid_a != NULL) {
crc2 = -1;
Msg.MsgIdCRC = upd_crc32(fmsg->msgid_a, crc2, strlen(fmsg->msgid_a));
}
if (fmsg->reply_a != NULL) {
crc2 = -1;
Msg.ReplyCRC = upd_crc32(fmsg->reply_a, crc2, strlen(fmsg->reply_a));
}
if (Msg_Open(msgs.Base)) {
if (Msg_Lock(30L)) {
rewind(ofp);
fgets(temp, 2048, ofp); /* "Eat" the first line AREA:... */
Msg_Write(ofp);
Msg_AddMsg();
Msg_UnLock();
echo_in++;
Syslog('+', "Newsgate %s => %s msg %ld", msgs.Newsgroup, msgs.Tag, Msg.Id);
}
Msg_Close();
StatAdd(&msgs.Received, 1);
time(&msgs.LastRcvd);
StatAdd(&mgroup.MsgsRcvd, 1);
time(&mgroup.LastDate);
}
/*
* Now start exporting this echomail.
*/
First = TRUE;
while (GetMsgSystem(&Link, First)) {
First = FALSE;
if ((Link.aka.zone) && (Link.sendto) && (!Link.pause) && (!Link.cutoff)) {
if (SearchNode(Link.aka)) {
StatAdd(&nodes.MailSent, 1L);
UpdateNode();
SearchNode(Link.aka);
}
echo_out++;
Syslog('n', "Export to %s", aka2str(Link.aka));
From = fido2faddr(msgs.Aka);
EchoOut(From, Link.aka, ofp, fmsg->flags, 0, fmsg->date);
tidy_faddr(From);
}
}
free(fromname);
free(toname);
free(subj);
fclose(ofp);
} while (needsplit);
tidy_falist(&sbl);
tidy_falist(&ptl);
free(temp);
news_imp++;
tidyrfc(msg);
tidy_ftnmsg(fmsg);
UpdateMsgs();
return RETVAL_OK;
}
int get_xover(char *grpname, long startnr, long endnr, List **art)
{
char cmd[81], *ptr, *ptr2, *resp, *p;
int retval, dupe, done = FALSE;
long nr;
unsigned long crc;
POverview pov;
sprintf(cmd, "XOVER %ld-%ld\r\n", startnr, endnr);
if ((retval = nntp_cmd(cmd, 224))) {
switch (retval) {
case 412:
WriteError("No newsgroup selected");
return RETVAL_NOXOVER;
case 502:
WriteError("Permission denied");
return RETVAL_NOXOVER;
case 420:
Syslog('n', "No articles in group %s", grpname);
return RETVAL_OK;
}
}
while (done == FALSE) {
resp = nntp_receive();
if ((strlen(resp) == 1) && (strcmp(resp, ".") == 0)) {
done = TRUE;
} else {
Marker();
pov = xoverview;
ptr = resp;
ptr2 = ptr;
/*
* First item is the message number.
*/
while (*ptr2 != '\0' && *ptr2 != '\t')
ptr2++;
if (*ptr2 != '\0')
*(ptr2) = '\0';
nr = atol(ptr);
ptr = ptr2;
ptr++;
/*
* Search the message-id
*/
while (*ptr != '\0' && pov != NULL && strcmp(pov->header, "Message-ID:") != 0) {
/*
* goto the next field, past the tab.
*/
pov = pov->next;
while (*ptr != '\t' && *ptr != '\0')
ptr++;
if (*ptr != '\0')
ptr++;
}
if (*ptr != '\0' && pov != NULL) {
/*
* Found it, now find start of msgid
*/
while (*ptr != '\0' && *ptr != '<')
ptr++;
if(ptr != '\0') {
ptr2 = ptr;
while(*ptr2 != '\0' && *ptr2 != '>')
ptr2++;
if (*ptr2 != '\0') {
*(ptr2+1) = '\0';
p = xstrcpy(ptr);
p = xstrcat(p, grpname);
crc = str_crc32(p);
dupe = CheckDupe(crc, D_NEWS, CFG.nntpdupes);
fill_artlist(art, ptr, nr, dupe);
free(p);
if (CFG.slow_util && do_quiet)
usleep(1);
}
}
}
}
}
return RETVAL_OK;
}
int get_xoverview(void)
{
int retval, len, full, done = FALSE;
char *resp;
POverview tmp, curptr = NULL;
Syslog('n', "Getting overview format list");
if ((retval = nntp_cmd((char *)"LIST overview.fmt\r\n", 215)) == 0) {
while (done == FALSE) {
resp = nntp_receive();
if ((strcmp(resp, ".") == 0) && (strlen(resp) == 1)) {
done = TRUE;
} else {
len = strlen(resp);
/*
* Check for the full flag, which means the field name
* is in the xover string.
*/
full = (strstr(resp, ":full") == NULL) ? FALSE : TRUE;
/*
* Now get rid of everything back to :
*/
while (resp[len] != ':')
resp[len--] = '\0';
len++;
tmp = malloc(sizeof(Overview));
tmp->header = calloc(len + 1, sizeof(char));
strncpy(tmp->header, resp, len);
tmp->header[len] = '\0';
tmp->next = NULL;
tmp->field = NULL;
tmp->fieldlen = 0;
tmp->full = full;
if (curptr == NULL) {
/* at head of list */
curptr = tmp;
xoverview = tmp;
} else {
/* add to linked list */
curptr->next = tmp;
curptr = tmp;
}
}
}
if ((tmp = xoverview) != NULL) {
Syslog('N', "--Xoverview.fmt list");
while (tmp != NULL) {
if (tmp->header != NULL) {
Syslog('N', "item = %s -- full = %s", tmp->header, tmp->full ? "True":"False");
}
tmp = tmp->next;
}
}
} else {
return 1;
}
return 0;
}
int needputrfc(rfcmsg *msg)
{
faddr *ta;
/* 0-junk, 1-kludge, 2-pass */
// Syslog('M', "needputrfc(%s)", printable(msg->key,0));
if ((msg->key == NULL) || (strlen(msg->key) == 0)) return 0;
if (!strcasecmp(msg->key,"X-UUCP-From")) return -1;
if (!strcasecmp(msg->key,"X-Body-Start")) return -1;
if (!strncasecmp(msg->key,".",1)) return 0;
if (!strncasecmp(msg->key,"X-FTN-",6)) return 0;
if (!strncasecmp(msg->key,"X-Fsc-",6)) return 0;
if (!strncasecmp(msg->key,"X-ZC-",5)) return 0;
if (!strcasecmp(msg->key,"X-Gateway")) return 0;
if (!strcasecmp(msg->key,"Path")) return 0;
if (!strcasecmp(msg->key,"Newsgroups")) {
if ((hdr((char *)"X-Origin-Newsgroups",msg)))
return 0;
else if (strstr(msg->val,","))
return 1;
else
return 0;
}
if (!strcasecmp(msg->key,"X-Origin-Newsgroups")) {
if (strstr(msg->val,","))
return 1;
else
return 0;
}
if (!strcasecmp(msg->key,"Control")) {
if (CFG.allowcontrol) {
if (strstr(msg->val,"cancel"))
return 1;
else
return 0;
} else
return 0;
}
if (!strcasecmp(msg->key,"Return-Path")) return 1;
if (!strcasecmp(msg->key,"Xref")) return 0;
if (!strcasecmp(msg->key,"Approved")) return removeapproved ? -1:2;
if (!strcasecmp(msg->key,"X-URL")) return 0;
if (!strcasecmp(msg->key,"Return-Receipt-To")) return removereturnto? 0:1;
if (!strcasecmp(msg->key,"Notice-Requested-Upon-Delivery-To")) return 0;
if (!strcasecmp(msg->key,"Received")) return 0;
if (!strcasecmp(msg->key,"From")) {
if ((ta = parsefaddr(msg->val))) {
tidy_faddr(ta);
return 0;
} else {
return 2;
}
}
if (!strcasecmp(msg->key,"To")) {
return 0;
}
if (!strcasecmp(msg->key,"Cc")) return 2;
if (!strcasecmp(msg->key,"Bcc")) return 0;
if (!strcasecmp(msg->key,"Reply-To")) {
if ((ta = parsefaddr(msg->val))) {
tidy_faddr(ta);
return -1;
} else
return removereplyto ?0:4;
}
if (!strcasecmp(msg->key,"Lines")) return 0;
if (!strcasecmp(msg->key,"Date")) return 0;
if (!strcasecmp(msg->key,"Subject")) {
if ((msg->val) && (strlen(msg->val) > MAXSUBJ))
return 2;
else
return 0;
}
if (!strcasecmp(msg->key,"Organization")) return 1;
if (!strcasecmp(msg->key,"Comment-To")) return 0;
if (!strcasecmp(msg->key,"X-Comment-To")) return 0;
if (!strcasecmp(msg->key,"X-Apparently-To")) return 0;
if (!strcasecmp(msg->key,"Apparently-To")) return 0;
if (!strcasecmp(msg->key,"X-Fidonet-Comment-To")) return 0;
if (!strcasecmp(msg->key,"Keywords")) return 2;
if (!strcasecmp(msg->key,"Summary")) return 2;
if (!strcasecmp(msg->key,"MIME-Version")) return removemime ?0:1;
if (!strcasecmp(msg->key,"Content-Type")) return removemime ?0:1;
if (!strcasecmp(msg->key,"Content-Length")) return removemime ?0:1;
if (!strcasecmp(msg->key,"Content-Transfer-Encoding")) return removemime ?0:1;
if (!strcasecmp(msg->key,"Content-Name")) return 2;
if (!strcasecmp(msg->key,"Content-Description")) return 2;
if (!strcasecmp(msg->key,"Message-ID")) return removemsgid ?0:1;
if (!strcasecmp(msg->key,"References")) return removeref ?0:1;
if (!strcasecmp(msg->key,"Supersedes")) return removesupersedes ?0:1;
if (!strcasecmp(msg->key,"Distribution")) return ftnorigin ?0:0;
if (!strcasecmp(msg->key,"X-Newsreader")) return 0;
if (!strcasecmp(msg->key,"X-Mailer")) return 0;
if (!strcasecmp(msg->key,"User-Agent")) return 0;
if (!strncasecmp(msg->key,"NNTP-",5)) return 0;
if (!strncasecmp(msg->key,"X-Trace",7)) return 0;
if (!strncasecmp(msg->key,"X-Complaints",12)) return 0;
if (!strncasecmp(msg->key,"X-MSMail",9)) return 0;
if (!strncasecmp(msg->key,"X-MimeOLE",9)) return 0;
if (!strncasecmp(msg->key,"X-MIME-Autoconverted",20)) return 0;
if (!strcasecmp(msg->key,"X-Origin-Date")) return 0;
if (!strncasecmp(msg->key,"X-PGP-",6)) return 0;
if (!strncasecmp(msg->key,"Resent-",7)) return 0;
if (!strcasecmp(msg->key,"X-Mailing-List")) return 0;
if (!strcasecmp(msg->key,"X-Loop")) return 0;
if (!strcasecmp(msg->key,"Precedence")) return 0;
/*if (!strcasecmp(msg->key,"")) return ;*/
return 1;
}