1553 lines
44 KiB
C
1553 lines
44 KiB
C
/*****************************************************************************
|
|
*
|
|
* $Id$
|
|
* Purpose ...............: Gate netmail->email or echomail->news
|
|
*
|
|
*****************************************************************************
|
|
* Copyright (C) 1997-2005
|
|
*
|
|
* 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
*****************************************************************************/
|
|
|
|
#include "../config.h"
|
|
#include "../lib/mbselib.h"
|
|
#include "../lib/users.h"
|
|
#include "../lib/mbsedb.h"
|
|
#include "rollover.h"
|
|
#include "aliasdb.h"
|
|
#include "postemail.h"
|
|
#include "backalias.h"
|
|
#include "msgflags.h"
|
|
#include "rfc2ftn.h"
|
|
#include "ftn2rfc.h"
|
|
|
|
|
|
#define KWDCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
|
#define MAXPATH 73
|
|
#define BOUNDARY 79
|
|
|
|
|
|
/*
|
|
* Global variables
|
|
*/
|
|
extern int news_in; /* Total news articles */
|
|
extern int news_out; /* News articles posted */
|
|
extern int news_bad; /* News articles refused */
|
|
extern int defaultrfcchar; /* Default RFC charset */
|
|
extern int defaultftnchar; /* Default FTN charset */
|
|
|
|
int newsopen = FALSE; /* News tempfile status */
|
|
FILE *nfp; /* News tempfile */
|
|
|
|
|
|
void fill_rlist(fa_list **, char *);
|
|
void fill_rlist(fa_list **fap, char *str)
|
|
{
|
|
fa_list *tmp;
|
|
faddr *ta;
|
|
static unsigned int oldnet;
|
|
char *buf, *p, *q;
|
|
|
|
if ((str == NULL) || (*str == '\0'))
|
|
return;
|
|
|
|
Syslog('N' ,"fill_rlist %s",str);
|
|
buf = xstrcpy(str);
|
|
for (p = buf, q = strchr(p,'!'); *p; p = q, q = strchr(p,'!')) {
|
|
if (q)
|
|
*q++='\0';
|
|
else
|
|
q=p+strlen(p);
|
|
if ((ta = parsefaddr(p))) {
|
|
if (ta->net == 0)
|
|
ta->net=oldnet;
|
|
else
|
|
oldnet=ta->net;
|
|
tmp=(fa_list *)malloc(sizeof(fa_list));
|
|
tmp->next=*fap;
|
|
tmp->addr=ta;
|
|
*fap=tmp;
|
|
}
|
|
}
|
|
free(buf);
|
|
for (tmp=*fap;tmp;tmp=tmp->next)
|
|
Syslog('N', "fill_rlist returns: %s",ascfnode(tmp->addr,0x06));
|
|
return;
|
|
}
|
|
|
|
|
|
static char *rbuf;
|
|
|
|
|
|
char *rfcmsgid(char *, faddr *);
|
|
char *rfcmsgid(char *msgid, faddr *bestaka)
|
|
{
|
|
char *p, *q, *r;
|
|
unsigned long id = 0L;
|
|
faddr *ta = NULL;
|
|
|
|
if (msgid == NULL)
|
|
return NULL;
|
|
|
|
/*
|
|
* +40 for the additionnal stuff we need to write, should be enough
|
|
*/
|
|
rbuf = malloc(strlen(msgid) + 40);
|
|
if ((r = strrchr(msgid,'\n')))
|
|
*r = '\0';
|
|
|
|
/*
|
|
* sometimes there is "^aMSGID: 1:23/45@@domain 152ad589"
|
|
*/
|
|
if ((p = strstr(msgid, "@@"))) {
|
|
*p='\0';
|
|
strcat(msgid, p+1);
|
|
} else if ((p = strstr(msgid,"@ "))) {
|
|
/*
|
|
* other times there is "^aMSGID: 1:23/45@ 152ad589"
|
|
*/
|
|
*p='\0';
|
|
strcat(msgid,p+1);
|
|
}
|
|
|
|
if ((p=strrchr(msgid,' '))) {
|
|
/*
|
|
* here we have a parseable address
|
|
*/
|
|
*p = '\0';
|
|
sscanf(p+1, "%lx", &id);
|
|
ta = parsefnode(msgid);
|
|
*p=' ';
|
|
}
|
|
|
|
if (id != 0L) {
|
|
/* if we only check for (ta) a Message-ID like
|
|
* <123456.7890@internet.domain> will be recognized as
|
|
* a fidonet one (ta->node=123456, ta->point=7890,
|
|
* ta->domain="internet", but ta->net=0) which obviously
|
|
* isn't the case. By cheking also (ta->net) we avoid that
|
|
*/
|
|
if ((ta) && (ta->net)) {
|
|
sprintf(rbuf, "<%lu@%s.ftn>", id, ascinode(ta,0x1f));
|
|
} else {
|
|
p = xstrcpy(msgid);
|
|
if ((q = strchr(p,' ')))
|
|
*q = '\0';
|
|
/* ### Modified by P.Saratxaga on 18 Aug 1995 */
|
|
if (strstr(p, "@")) {
|
|
/* "mid__<local@domain>" are generated by gigo */
|
|
if (!strncmp(p, "mid__<", 6)) {
|
|
sprintf(rbuf, "%s", p+6);
|
|
while ((q = strstr(rbuf, ">_<")))
|
|
*(q+1) = ' ';
|
|
}
|
|
/* "mid__local@domain" are also generated by gigo */
|
|
else if (!strncmp(p, "mid__", 5))
|
|
sprintf(rbuf, "<%s>", p+5);
|
|
/* "wgmid$<local@domain>" */
|
|
else if (!strncmp(p, "wgmid$<", 7))
|
|
sprintf(rbuf, "%s", p+6);
|
|
/* in case we have "<local@domain>" */
|
|
else if (!strncmp(p, "<", 1))
|
|
sprintf(rbuf, "%s", p);
|
|
/* or "local@domain" */
|
|
else
|
|
sprintf(rbuf, "<%s>", p);
|
|
while ((q = strchr(rbuf, '@')) != strrchr(rbuf, '@')) {
|
|
/* we (still) have more than one @ */
|
|
*q = '%';
|
|
}
|
|
} else {
|
|
sprintf(rbuf, "<%lu@%s>", id, p);
|
|
}
|
|
free(p);
|
|
}
|
|
} else {
|
|
sprintf(rbuf, "<%lu@%s.ftn>", (unsigned long)sequencer(), ascinode(bestaka,0x1f));
|
|
}
|
|
tidy_faddr(ta);
|
|
if (r)
|
|
*r='\n';
|
|
return rbuf;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* check address for localness, substitute alises and replace it *in place*
|
|
*/
|
|
void substitude(char *);
|
|
void substitute(char *buf)
|
|
{
|
|
faddr *fa;
|
|
char *l,*r,*p=NULL;
|
|
int inquotes,inbrackets;
|
|
|
|
Syslog('m', "to address before subst: \"%s\"",buf);
|
|
if ((l=strchr(buf,'<')) && (r=strchr(buf,'>')) && (l < r)) {
|
|
l++;
|
|
*r='\0';
|
|
} else
|
|
l=buf;
|
|
while (*l == ' ')
|
|
l++;
|
|
for (r=l,inquotes=0,inbrackets=0;*r;r++)
|
|
switch (*r) {
|
|
case '"': inquotes=(!inquotes); break;
|
|
case ',':
|
|
case ' ': if (!inquotes && !inbrackets) *r='\0'; break;
|
|
case '(': if (!inquotes) inbrackets++; break;
|
|
case ')': if (!inquotes && inbrackets) inbrackets--; break;
|
|
default: break;
|
|
}
|
|
if ((fa = parsefaddr(l))) {
|
|
Syslog('m', "it is an ftn address: %s",ascfnode(fa,0x7f));
|
|
if (is_local(fa)) {
|
|
Syslog('m', "it is local");
|
|
sprintf(buf,"%s",fa->name);
|
|
if (!strchr(buf,'@') && (p=strrchr(buf,'%')))
|
|
*p='@';
|
|
if (!strchr(buf,'@')) {
|
|
/*
|
|
* Lookup the name first in the alias database, then
|
|
* the userbase and finally check the password file
|
|
* (gecos->username). If not found it's and error.
|
|
*/
|
|
if ((p = lookup(buf)))
|
|
strcpy(buf, p);
|
|
else if (SearchUser(buf))
|
|
sprintf(buf, "%s@%s", usr.Name, CFG.sysdomain);
|
|
else if (!strcasecmp(buf,"sysop"))
|
|
strcpy(buf,"postmaster");
|
|
else
|
|
sprintf(buf,"%s",ascinode(fa,0x7f));
|
|
}
|
|
} else {
|
|
WriteError("substitute(%s) it is not local, may not happen", buf);
|
|
sprintf(buf,"%s",ascinode(fa,0x7f));
|
|
}
|
|
tidy_faddr(fa);
|
|
} else {
|
|
Syslog('m', "it is not ftn address");
|
|
for (r=buf;*l;l++,r++)
|
|
*r=*l;
|
|
*r='\0';
|
|
}
|
|
if (buf[0] == '\0')
|
|
strcpy(buf,"postmaster");
|
|
Syslog('m', "to address after subst: \"%s\"",buf);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Lines to send, if it is a newsarticle, the Message-Id is checked.
|
|
*/
|
|
void Send(int, char *);
|
|
void Send(int newsmode, char *outstr)
|
|
{
|
|
char *p;
|
|
unsigned long crc;
|
|
|
|
charwrite(outstr, nfp);
|
|
Syslog('m', "+ %s", printable(outstr, 0));
|
|
|
|
if (newsmode) {
|
|
Striplf(outstr);
|
|
if (strncmp(outstr, (char*)"Message-ID: ", 12) == 0) {
|
|
/*
|
|
* The Message-ID that is sent to the newsserver is stored in
|
|
* the dupes database. The database isn't checked for dupes, this
|
|
* message is already checked for dupes. The function that will
|
|
* pull news articles from the news server will check the dupes
|
|
* database and thus will not fetch this local posted article.
|
|
*/
|
|
p = xstrcpy(outstr+12);
|
|
p = xstrcat(p, msgs.Newsgroup);
|
|
crc = str_crc32(p);
|
|
CheckDupe(crc, D_NEWS, CFG.nntpdupes);
|
|
free(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Gate FTN style netmail->email or echomail->news.
|
|
*
|
|
* 0 - All seems well.
|
|
* 1 - Something went wrong.
|
|
* 4 - Unable to open temporary file
|
|
*
|
|
*/
|
|
int ftn2rfc(faddr *f, faddr *t, char *subj, char *origline, time_t mdate, int flags, FILE *pkt)
|
|
{
|
|
int rrq, result = 1, waskludge = FALSE, badkludge;
|
|
int bNeedToGetAddressFromMsgid = (int)NULL, newsmode = 0, lines, pass, count, first;
|
|
char *newsgroup = NULL, *charset = NULL;
|
|
char *temp, *p, *q, *r, *l, *b, *To = NULL, buf[4096], c, MailFrom[128], MailTo[128];
|
|
time_t now;
|
|
rfcmsg *kmsg = NULL, **tmsg, *qmsg, *msg = NULL;
|
|
off_t endmsg_off, tear_off, orig_off, via_off;
|
|
faddr *o, *bestaka, *ta, *tfaddr;
|
|
FILE *fp;
|
|
fa_list *rlist, *tfa, *ftnpath = NULL;
|
|
struct utsname utsbuf;
|
|
|
|
temp = calloc(32768, sizeof(char));
|
|
tmsg = &kmsg;
|
|
tear_off = orig_off = via_off = 0L;
|
|
rbuf = NULL;
|
|
|
|
if ((fp = tmpfile()) == NULL) {
|
|
WriteError("$Unable to open temporary file");
|
|
free(temp);
|
|
return 4;
|
|
}
|
|
|
|
Syslog('M', "Message input start =============");
|
|
rewind(pkt);
|
|
while ((fgets(buf, sizeof(buf)-2, pkt)) != NULL) {
|
|
/*
|
|
* Simple test to see how large the buffer must be. 2048 bytes has been seen.
|
|
*/
|
|
if (strlen(buf) > (sizeof(buf) /2))
|
|
Syslog('+', "FTN: Possible bufferoverflow: line read %d bytes", strlen(buf));
|
|
if (strlen(buf) > 200) {
|
|
Syslog('M', "FTN: Next line should be %d characters", strlen(buf));
|
|
Syslogp('M', printable(buf, 200));
|
|
} else {
|
|
Syslogp('M', printable(buf, 0));
|
|
}
|
|
if ((buf[0] == '\1') || !strncmp(buf,"AREA:",5) || !strncmp(buf,"SEEN-BY",7)) { /* This is a kluge line */
|
|
waskludge = TRUE;
|
|
badkludge = FALSE;
|
|
if (buf[0] == '\1') {
|
|
l = buf+1;
|
|
if (!strncmp(l,"AREA:",5) || !strncmp(l,"SEEN-BY",7))
|
|
badkludge = TRUE;
|
|
} else
|
|
l = buf;
|
|
if (*l == '\n')
|
|
badkludge = TRUE;
|
|
else
|
|
while (isspace(*l))
|
|
l++;
|
|
if (strncmp(l, "RFC-", 4))
|
|
for (p = l; *p; p++)
|
|
if ((*p != '\n') && (((*p)&0x7f) < ' '))
|
|
badkludge = TRUE;
|
|
p = strchr(l,':');
|
|
r = strchr(l,' ');
|
|
if (p && (!r || (r > p)))
|
|
r = p;
|
|
else
|
|
p = r;
|
|
if (r == NULL)
|
|
badkludge = TRUE;
|
|
else if (!*(p+1) || (*(p+1)=='\n'))
|
|
badkludge = TRUE;
|
|
else {
|
|
c = *r;
|
|
*r = '\0';
|
|
if (strspn(l,KWDCHARS) != strlen(l))
|
|
badkludge = TRUE;
|
|
*r = c;
|
|
}
|
|
*tmsg = (rfcmsg *)malloc(sizeof(rfcmsg));
|
|
(*tmsg)->next = NULL;
|
|
if (badkludge) {
|
|
(*tmsg)->key = xstrcpy((char *)"KLUDGE");
|
|
p = printable(l,0);
|
|
r = p+strlen(p)-2;
|
|
if (strcmp(r,"\\n") == 0) {
|
|
*r++ = '\n';
|
|
*r = '\0';
|
|
}
|
|
(*tmsg)->val = xstrcpy(p);
|
|
} else {
|
|
*r++ = '\0';
|
|
while (isspace(*r))
|
|
r++;
|
|
(*tmsg)->key = xstrcpy(l);
|
|
(*tmsg)->val = xstrcpy(r);
|
|
}
|
|
tmsg = &((*tmsg)->next);
|
|
|
|
if (!strcmp(l,"Via") && (via_off == 0L)) {
|
|
via_off = ftell(fp);
|
|
Syslog('m', "^AVia \"%s\" at offset %ld", printable(buf, 0), (long)via_off);
|
|
}
|
|
} else {
|
|
/*
|
|
* this is not a kludge line
|
|
*/
|
|
if (waskludge && (isspace(buf[0])))
|
|
fputs("\n",fp); /* first body line is not RFC hdr */
|
|
waskludge=0;
|
|
if ((!strncmp(buf,"---",3)) && (buf[3] != '-')) {
|
|
tear_off=ftell(fp);
|
|
if ((hdr((char *)"Tearline",kmsg) == NULL)) {
|
|
*tmsg=(rfcmsg *)malloc(sizeof(rfcmsg));
|
|
(*tmsg)->next=NULL;
|
|
(*tmsg)->key=xstrcpy((char *)"Tearline");
|
|
if (strlen(buf+3) == strspn(buf+3," \t\r\n"))
|
|
(*tmsg)->val=xstrcpy((char *)"(none)\n");
|
|
else
|
|
(*tmsg)->val=xstrcpy(buf+4);
|
|
tmsg=&((*tmsg)->next);
|
|
}
|
|
} else if (!strncmp(buf," * Origin:",10)) {
|
|
orig_off = ftell(fp);
|
|
*tmsg = (rfcmsg *)malloc(sizeof(rfcmsg));
|
|
(*tmsg)->next = NULL;
|
|
(*tmsg)->key = xstrcpy((char *)"Origin");
|
|
(*tmsg)->val = xstrcpy(buf+11);
|
|
tmsg = &((*tmsg)->next);
|
|
Syslog('M', "origin \"%s\" at offset %ld", buf,(long)orig_off);
|
|
p = buf+10;
|
|
while (*p == ' ')
|
|
p++;
|
|
if ((l = strrchr(p,'(')) && (r = strrchr(p,')')) && (l < r)) {
|
|
/*
|
|
* Extract origin address from the Origin line.
|
|
*/
|
|
*l = '\0';
|
|
*r = '\0';
|
|
l++;
|
|
if ((o = parsefnode(l))) {
|
|
f->point = o->point;
|
|
f->node = o->node;
|
|
f->net = o->net;
|
|
f->zone = o->zone;
|
|
if (o->domain)
|
|
f->domain = o->domain;
|
|
o->domain = NULL;
|
|
tidy_faddr(o);
|
|
}
|
|
} else {
|
|
bNeedToGetAddressFromMsgid = !NULL;
|
|
Syslog('+', "Couldn't find address in origin line (%s of %s, [%s])",
|
|
f->name, ascfnode(f, 0x1f), hdr((char *)"Origin", kmsg));
|
|
if (*(l = p+strlen(p)-1) == '\n')
|
|
*l = '\0';
|
|
}
|
|
for (l = p+strlen(p)-1; *l == ' '; l--)
|
|
*l = '\0';
|
|
origline = xstrcpy(p);
|
|
} else if (!strncmp(buf," * Message split",16)) {
|
|
*tmsg = (rfcmsg *)malloc(sizeof(rfcmsg));
|
|
(*tmsg)->next = NULL;
|
|
(*tmsg)->key = xstrcpy((char *)"Split");
|
|
(*tmsg)->val = xstrcpy((char *)"already\n");
|
|
tmsg=&((*tmsg)->next);
|
|
Syslog('m', "Split indicator found");
|
|
}
|
|
fputs(buf,fp);
|
|
}
|
|
}
|
|
Syslog('M', "Message input end ===============");
|
|
|
|
if (bNeedToGetAddressFromMsgid && (p = hdr((char *)"MSGID", kmsg))) {
|
|
Syslog('m', "Need To Get Address From Msgid start...");
|
|
l = p;
|
|
while(isspace(*l) && *l)
|
|
l++;
|
|
r = strchr(l, ' ');
|
|
if(r) {
|
|
*r-- = '\0';
|
|
while(isspace(*r) && *r)
|
|
r--;
|
|
}
|
|
if (l && r && l > r) {
|
|
if ((o = parsefnode(l))) {
|
|
f->point = o->point;
|
|
f->node = o->node;
|
|
f->net = o->net;
|
|
f->zone = o->zone;
|
|
if (o->domain)
|
|
f->domain = o->domain;
|
|
o->domain = NULL;
|
|
tidy_faddr(o);
|
|
Syslog('+', "Origin from: %s (src MSGID)", ascfnode(f,0x7f));
|
|
}
|
|
}
|
|
}
|
|
|
|
endmsg_off=ftell(fp);
|
|
if ((tear_off) && (tear_off < endmsg_off))
|
|
endmsg_off = tear_off;
|
|
if ((orig_off) && (orig_off < endmsg_off))
|
|
endmsg_off = orig_off;
|
|
if ((via_off) && (via_off < endmsg_off))
|
|
endmsg_off = via_off;
|
|
|
|
rewind(fp);
|
|
msg = parsrfc(fp);
|
|
bestaka = bestaka_s(f);
|
|
rewind(fp);
|
|
|
|
/*
|
|
* Get characterset encoding from kludge or rfc header
|
|
*/
|
|
p = hdr((char *)"CHRS", kmsg);
|
|
if (p == NULL)
|
|
p = hdr((char *)"CHARSET", kmsg);
|
|
if (p == NULL)
|
|
p = hdr((char *)"CODEPAGE", kmsg);
|
|
if (p) {
|
|
while (*p && isspace(*p))
|
|
p++;
|
|
Striplf(p);
|
|
charset = xstrcpy(p);
|
|
Syslog('m', "Charset from ftn \"%s\"", printable(charset, 0));
|
|
} else {
|
|
p=hdr((char *)"Content-Type",msg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"RFC-Content-Type",kmsg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"Content-Type",kmsg);
|
|
if (p) {
|
|
q = strtok(p, " \n\0");
|
|
q = strtok(NULL, " \n\0");
|
|
while (*q && isspace(*q))
|
|
q++;
|
|
Syslog('m', "charset part: %s", printable(q, 0));
|
|
if (q && (strncasecmp(q, "charset=", 8) == 0)) {
|
|
charset = xstrcpy(q + 8);
|
|
Syslog('m', "Charset from rfc \"%s\"", printable(charset, 0));
|
|
}
|
|
} else {
|
|
charset = xstrcpy((char *)"iso-8859-1");
|
|
Syslog('m', "No charset, setting default to iso-8859-1");
|
|
}
|
|
}
|
|
|
|
if (kmsg && !strcmp(kmsg->key,"AREA")) {
|
|
/*
|
|
* The msgs record is already loaded.
|
|
*/
|
|
newsgroup = xstrcpy(msgs.Newsgroup);
|
|
Syslog('M', "newsgroup %s", printable(newsgroup, 0));
|
|
newsmode = TRUE;
|
|
} else
|
|
newsmode = FALSE;
|
|
Syslog('m', "Got %s message", newsmode?"echo":"netmail");
|
|
|
|
/*
|
|
* fsc-0038 defines "^aDOMAIN: othernet 99:12/34 fidonet 2:293/2219"
|
|
*/
|
|
if ((p=hdr((char *)"DOMAIN",kmsg)) && (!strchr(p,'@'))) {
|
|
strncpy(buf,p,sizeof(buf)-1);
|
|
buf[sizeof(buf)-1]='\0';
|
|
l=strtok(buf," \n");
|
|
p=strtok(NULL," \n");
|
|
r=strtok(NULL," \n");
|
|
q=strtok(NULL," \n");
|
|
if ((ta=parsefnode(p))) {
|
|
t->point=ta->point;
|
|
t->node=ta->node;
|
|
t->net=ta->net;
|
|
t->zone=ta->zone;
|
|
tidy_faddr(ta);
|
|
}
|
|
t->domain=xstrcpy(l);
|
|
if ((ta=parsefnode(q))) {
|
|
f->point=ta->point;
|
|
f->node=ta->node;
|
|
f->net=ta->net;
|
|
f->zone=ta->zone;
|
|
tidy_faddr(ta);
|
|
}
|
|
f->domain=xstrcpy(r);
|
|
} else if ((p=hdr((char *)"INTL",kmsg))) {
|
|
strncpy(buf,p,sizeof(buf)-1);
|
|
buf[sizeof(buf)-1]='\0';
|
|
l=strtok(buf," \n");
|
|
r=strtok(NULL," \n");
|
|
if ((ta=parsefnode(l))) {
|
|
t->point=ta->point;
|
|
t->node=ta->node;
|
|
t->net=ta->net;
|
|
t->zone=ta->zone;
|
|
if (ta->domain) {
|
|
if (t->domain)
|
|
free(t->domain);
|
|
t->domain=ta->domain;
|
|
ta->domain=NULL;
|
|
}
|
|
tidy_faddr(ta);
|
|
}
|
|
if ((ta=parsefnode(r))) {
|
|
f->point=ta->point;
|
|
f->node=ta->node;
|
|
f->net=ta->net;
|
|
f->zone=ta->zone;
|
|
if (ta->domain) {
|
|
if (f->domain)
|
|
free(f->domain);
|
|
f->domain=ta->domain;
|
|
ta->domain=NULL;
|
|
}
|
|
tidy_faddr(ta);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* fidogate generates "^aDOMAIN: Z2@fidonet"
|
|
*/
|
|
if ((f->domain==NULL) && ((p=hdr((char *)"DOMAIN",kmsg)) && (q=strchr(p,'@')))) {
|
|
*q='\0';
|
|
f->domain=xstrcpy(q+1);
|
|
*q='@';
|
|
}
|
|
|
|
if ((p=hdr((char *)"FMPT",kmsg)))
|
|
f->point=atoi(p);
|
|
if ((p=hdr((char *)"TOPT",kmsg)))
|
|
t->point=atoi(p);
|
|
|
|
if (!newsmode) {
|
|
Syslog('m', "final from: %s",ascfnode(f,0xff));
|
|
Syslog('m', "final to: %s",ascfnode(t,0xff));
|
|
}
|
|
|
|
if (!newsmode) {
|
|
p=hdr((char *)"Resent-To",msg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"To",msg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"RFC-Resent-To",kmsg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"RFC-To",kmsg);
|
|
if (p && is_local(t)) {
|
|
while (*p == ' ')
|
|
p++;
|
|
strncpy(buf, p, sizeof(buf) -1);
|
|
if (*(p = buf + strlen(buf) -1) == '\n')
|
|
*p='\0';
|
|
} else
|
|
sprintf(buf,"%s",ascinode(t,0x7f));
|
|
substitute(buf);
|
|
Syslog('+', "mail from %s to %s",ascfnode(f,0x7f),buf);
|
|
To = xstrcpy(buf);
|
|
|
|
p = NULL;
|
|
p = hdr((char *)"Return-Path",msg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"RFC-Return-Path",kmsg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"Return-Path",kmsg);
|
|
if ((CFG.EmailMode == E_PRMISP) && (p == NULL))
|
|
p=hdr((char *)"From",msg);
|
|
if (p)
|
|
sprintf(MailFrom, "%s", p);
|
|
else
|
|
sprintf(MailFrom, "%s", ascinode(f,0x7f));
|
|
Syslog('m', "MailFrom: %s", MailFrom);
|
|
|
|
if (To)
|
|
sprintf(MailTo, "%s", To);
|
|
else
|
|
sprintf(MailTo, "%s", t->name);
|
|
Syslog('m', "MailTo: %s", MailTo);
|
|
|
|
/*
|
|
* Because we need the same stream for news and email
|
|
* we need to check if the newsfile is already open.
|
|
*/
|
|
if (newsopen) {
|
|
fclose(nfp);
|
|
newsopen = FALSE;
|
|
}
|
|
|
|
if ((nfp = tmpfile()) == NULL) {
|
|
WriteError("$Unable to open temporary file");
|
|
return 4;
|
|
}
|
|
|
|
Syslog('m', "Prepare is ready");
|
|
}
|
|
|
|
/*
|
|
* Setup charset conversion
|
|
*/
|
|
charset_set_in_out(charset, getrfcchrs(msgs.Charset));
|
|
|
|
if (newsmode) {
|
|
/*
|
|
* Open temporary newsfile, append messages if it already exists.
|
|
*/
|
|
if (!newsopen) {
|
|
p = calloc(PATH_MAX, sizeof(char));
|
|
sprintf(p, "%s/tmp/newsout", getenv("MBSE_ROOT"));
|
|
if ((nfp = fopen(p, "a")) == NULL) {
|
|
WriteError("$Can't open %s", p);
|
|
free(p);
|
|
return 2;
|
|
}
|
|
free(p);
|
|
newsopen = TRUE;
|
|
}
|
|
|
|
if ((p=hdr((char *)"Path",msg)) == NULL)
|
|
p=hdr((char *)"RFC-Path",kmsg);
|
|
rlist=NULL;
|
|
fill_rlist(&rlist, p);
|
|
for (qmsg = kmsg; qmsg; qmsg = qmsg->next)
|
|
if (strcasecmp(qmsg->key, "SPTH") == 0)
|
|
fill_list(&ftnpath, qmsg->val, &rlist);
|
|
for (qmsg = kmsg; qmsg; qmsg = qmsg->next)
|
|
if (strcasecmp(qmsg->key, "PATH") == 0)
|
|
fill_list(&ftnpath, qmsg->val, &rlist);
|
|
tidy_falist(&rlist);
|
|
|
|
/*
|
|
* Build Path: headerline
|
|
*/
|
|
q = xstrcpy((char *)"Path: ");
|
|
if (CFG.newsfeed == FEEDUUCP) {
|
|
/*
|
|
* If we don't run our own newsserver we have to simulate and
|
|
* add the UUCP nodename here.
|
|
*/
|
|
memset(&utsbuf, 0, sizeof(utsbuf));
|
|
if (uname(&utsbuf)) {
|
|
WriteError("Can't get system nodename");
|
|
} else {
|
|
q = xstrcat(q, utsbuf.nodename);
|
|
q = xstrcat(q, (char *)"!");
|
|
}
|
|
}
|
|
tfaddr = fido2faddr(msgs.Aka);
|
|
q = xstrcat(q, ascinode(tfaddr, 0x07));
|
|
tidy_faddr(tfaddr);
|
|
q = xstrcat(q, (char *)"!");
|
|
if (ftnpath)
|
|
for (tfa=ftnpath->next;tfa;tfa=tfa->next) {
|
|
/* FIXME: possible memory leak */
|
|
q = xstrcat(q, ascinode(tfa->addr,0x1f));
|
|
q = xstrcat(q, (char *)"!");
|
|
}
|
|
tidy_falist(&ftnpath);
|
|
|
|
if (p) {
|
|
while (isspace(*p))
|
|
p++;
|
|
q = xstrcat(q, p);
|
|
} else
|
|
q = xstrcat(q, (char *)"not-for-mail");
|
|
sprintf(temp, "%s\n", q);
|
|
Send(newsmode, temp);
|
|
free(q);
|
|
|
|
if ((p = hdr((char *)"Newsgroups",msg))) {
|
|
/*
|
|
* The gate at puddle.fidonet.org put spaces in Newsgroups header
|
|
*/
|
|
if ((strstr(p,", "))) {
|
|
while ((r = strchr(p, ' '))) {
|
|
*r = '\0';
|
|
strcat(p,r+1);
|
|
}
|
|
}
|
|
}
|
|
if (p == NULL)
|
|
p=hdr((char *)"RFC-Newsgroups",kmsg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"Newsgroups",kmsg);
|
|
if (p) {
|
|
while (*p && isspace(*p))
|
|
p++;
|
|
sprintf(temp,"Newsgroups: %s\n",newsgroup);
|
|
Send(newsmode, temp);
|
|
sprintf(temp,"X-Origin-Newsgroups: %s",p);
|
|
Send(newsmode, temp);
|
|
} else {
|
|
sprintf(temp,"Newsgroups: %s\n",newsgroup);
|
|
Send(newsmode, temp);
|
|
}
|
|
|
|
p = hdr((char *)"Comment-To",msg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"X-Comment-To",msg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"To",msg);
|
|
if ((p) && (strcasecmp(p,"All\n"))) {
|
|
sprintf(temp,"X-Comment-To:%s", p);
|
|
Send(newsmode, temp);
|
|
} else {
|
|
if (p == NULL)
|
|
p=hdr((char *)"RFC-X-Comment-To",kmsg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"RFC-Comment-To",kmsg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"RFC-To",kmsg);
|
|
if ((p) && (strcasecmp(p,"All\n"))) {
|
|
sprintf(temp,"X-Comment-To: %s", p);
|
|
Send(newsmode, temp);
|
|
} else if ((t) && (t->name) && (strcasecmp(t->name,"All"))) {
|
|
sprintf(temp,"X-Comment-To: %s\n", t->name);
|
|
Send(newsmode, temp);
|
|
} else {
|
|
sprintf(temp,"X-Comment-To: All\n");
|
|
Send(newsmode, temp);
|
|
}
|
|
}
|
|
|
|
if ((p=hdr((char *)"Approved",msg))) {
|
|
sprintf(temp,"Approved:%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-Approved",kmsg))) {
|
|
sprintf(temp,"Approved: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"Approved",kmsg))) {
|
|
sprintf(temp,"Approved: %s",p);
|
|
Send(newsmode, temp);
|
|
}
|
|
|
|
} else { /* if newsmode */
|
|
now = time(NULL);
|
|
Syslog('m', "Should send Received: header for mbfido");
|
|
sprintf(temp, "Received: from %s\n", ascinode(f, 0x3f));
|
|
Send(FALSE, temp);
|
|
sprintf(temp, "\tby %s with FTN (mbfido v.%s) id AA%u\n", ascinode(bestaka,0x3f), VERSION, getpid());
|
|
Send(FALSE, temp);
|
|
sprintf(temp, "\t%s\n", rfcdate(now));
|
|
Send(FALSE, temp);
|
|
Syslog('m', "Is done now");
|
|
|
|
for (qmsg = kmsg; qmsg; qmsg = qmsg->next)
|
|
if (!strcasecmp(qmsg->key,"RFC-Received")) {
|
|
sprintf(temp, "%s: %s", qmsg->key+4, qmsg->val);
|
|
Send(FALSE, temp);
|
|
}
|
|
for (qmsg = msg; qmsg; qmsg = qmsg->next)
|
|
if (!strcasecmp(qmsg->key,"Received")) {
|
|
sprintf(temp, "%s:%s", qmsg->key, qmsg->val);
|
|
Send(FALSE, temp);
|
|
}
|
|
|
|
if ((p=hdr((char *)"Apparently-To",msg))) {
|
|
sprintf(temp, "Apparently-To: %s\n",p);
|
|
Send(FALSE, temp);
|
|
} else if ((p=hdr((char *)"RFC-Apparently-To",kmsg))) {
|
|
sprintf(temp, "Apparently-To: %s\n",p);
|
|
Send(FALSE, temp);
|
|
} else if ((p=hdr((char *)"Apparently-To",kmsg))) {
|
|
sprintf(temp, "Apparently-To: %s\n",p);
|
|
Send(FALSE, temp);
|
|
} else if ((is_local(t))) {
|
|
sprintf(temp, "Apparently-To: %s\n",buf);
|
|
Send(FALSE, temp);
|
|
}
|
|
|
|
if (flags & M_RRQ)
|
|
rrq=TRUE;
|
|
else
|
|
rrq=FALSE;
|
|
if (rrq && !hdr((char *)"RFC-Return-Receipt-To",kmsg) &&
|
|
!hdr((char *)"Return-Receipt-To",msg) &&
|
|
!hdr((char *)"RFC-Notice-Requested-Upon-Delivery-To",kmsg) &&
|
|
!hdr((char *)"Notice-Requested-Upon-Delivery-To",msg)) {
|
|
sprintf(temp,"Notice-Requested-Upon-Delivery-To: %s\n",buf);
|
|
Send(FALSE, temp);
|
|
}
|
|
|
|
if (t->name == NULL)
|
|
t->name=xstrcpy((char *)"Postmaster");
|
|
p=hdr((char *)"Resent-To",msg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"To",msg);
|
|
if (p) {
|
|
sprintf(temp,"To:%s",p);
|
|
Send(FALSE, temp);
|
|
} else {
|
|
if (p == NULL)
|
|
p=hdr((char *)"RFC-Resent-To",kmsg);
|
|
if (p == NULL)
|
|
p=hdr((char *)"RFC-To",kmsg);
|
|
if (p) {
|
|
Syslog('m', "2");
|
|
sprintf(temp,"To: %s\n",p);
|
|
Send(FALSE, temp);
|
|
} else if (is_local(t)) {
|
|
Syslog('m', "3");
|
|
sprintf(temp, "To: %s <%s>\n", t->name, buf);
|
|
Send(FALSE, temp);
|
|
} else {
|
|
Syslog('m', "4");
|
|
sprintf(temp,"To: %s\n",ascinode(t,0xff));
|
|
Send(FALSE, temp);
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((p = hdr((char *)"From",msg))) {
|
|
sprintf(temp, "From:%s", p);
|
|
Send(newsmode, temp);
|
|
} else if ((p = hdr((char *)"RFC-From",kmsg))) {
|
|
Syslog('m', "b");
|
|
sprintf(temp, "From: %s", p);
|
|
Send(newsmode, temp);
|
|
} else if ((p = hdr((char *)"From\n",kmsg))) {
|
|
Syslog('m', "c");
|
|
sprintf(temp, "From: %s", p);
|
|
Send(newsmode, temp);
|
|
} else if ((p = hdr((char *)"X-PcBoard-FROM",msg))) {
|
|
if (f->name) {
|
|
while (isspace(*p))
|
|
p++;
|
|
p[strlen(p)-1] = '\0';
|
|
sprintf(temp,"From: %s <%s>\n", f->name, p);
|
|
} else {
|
|
sprintf(temp,"From:%s\n", p);
|
|
}
|
|
Send(newsmode, temp);
|
|
} else if ((hdr((char *)"REPLYADDR",kmsg)) && (p=xstrcpy(hdr((char *)"REPLYADDR",kmsg)))) {
|
|
if (*(r=p+strlen(p)-1) == '\n')
|
|
*(r--)='\0';
|
|
while (isspace(*r))
|
|
*(r--)='\0';
|
|
q=xstrcpy(hdr((char *)"X-RealName",msg));
|
|
if (q == NULL)
|
|
q=xstrcpy(hdr((char *)"RealName",msg));
|
|
if (q == NULL)
|
|
q=xstrcpy(hdr((char *)"X-RealName",kmsg));
|
|
if (q == NULL)
|
|
q=xstrcpy(hdr((char *)"RealName",kmsg));
|
|
if (q) {
|
|
if (*(r=q+strlen(q)-1) == '\n')
|
|
*(r--)='\0';
|
|
while (isspace(*r))
|
|
*(r--)='\0';
|
|
for (l=q; isspace(*l); )
|
|
l++;
|
|
if ((*l == '\"') && (*r == '\"')) {
|
|
l++;
|
|
*r--='\0';
|
|
}
|
|
Syslog('m', "d");
|
|
sprintf(temp,"From: \"%s\" <%s>\n", l, p);
|
|
Send(newsmode, temp);
|
|
free(q);
|
|
} else if (f->name) {
|
|
Syslog('m', "e");
|
|
sprintf(temp,"From: \"%s\" <%s>\n", f->name, p);
|
|
Send(newsmode, temp);
|
|
} else {
|
|
Syslog('m', "f");
|
|
sprintf(temp,"From: %s\n",p);
|
|
Send(newsmode, temp);
|
|
}
|
|
free(p);
|
|
}
|
|
|
|
// if (p)
|
|
// sprintf(temp,"X-FTN-Sender: %s\n", ascinode(f,0xff));
|
|
// else
|
|
// sprintf(temp,"From: %s\n", ascinode(f,0xff));
|
|
// Send(newsmode, temp);
|
|
|
|
if ((p=hdr((char *)"Reply-To",msg))) {
|
|
sprintf(temp,"Reply-To:%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-Reply-To",kmsg))) {
|
|
sprintf(temp,"Reply-To: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"Reply-To",kmsg))) {
|
|
sprintf(temp,"Reply-To: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if (((p=backalias(f))) && strlen(CFG.sysdomain)) {
|
|
sprintf(temp,"Reply-To: %s@%s\n",p,CFG.sysdomain);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"REPLYADDR",kmsg))) {
|
|
sprintf(temp,"Reply-To: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"REPLYTO",kmsg))) {
|
|
ta = parsefaddr(p);
|
|
sprintf(temp,"Reply-To: %s\n",ascinode(ta, 0xff));
|
|
tidy_faddr(ta);
|
|
Send(newsmode, temp);
|
|
}
|
|
|
|
if ((p=hdr((char *)"Date",msg))) {
|
|
sprintf(temp,"Date:%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-Date",kmsg))) {
|
|
sprintf(temp,"Date: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"Date",kmsg))) {
|
|
sprintf(temp,"Date: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if (newsmode) {
|
|
/*
|
|
* Restamp future postings
|
|
*/
|
|
now = time(NULL);
|
|
if (mdate > now) {
|
|
Syslog('+', "Future posting: %s", rfcdate(mdate));
|
|
sprintf(temp,"Date: %s\n", rfcdate(now));
|
|
Send(newsmode, temp);
|
|
sprintf(temp,"X-Origin-Date: %s\n", rfcdate(mdate));
|
|
Send(newsmode, temp);
|
|
} else if ((mdate < now-14*24*60*60) && (mdate > time(&now)-21*24*60*60)) {
|
|
/*
|
|
* Restamp old postings
|
|
*/
|
|
Syslog('+', "Article too old, restamped: %s", rfcdate(mdate));
|
|
sprintf(temp,"Date: %s\n", rfcdate(now));
|
|
Send(newsmode, temp);
|
|
sprintf(temp,"X-Origin-Date: %s\n", rfcdate(mdate));
|
|
Send(newsmode, temp);
|
|
} else {
|
|
sprintf(temp,"Date: %s\n",rfcdate(mdate));
|
|
Send(newsmode, temp);
|
|
}
|
|
} else {
|
|
sprintf(temp,"Date: %s\n",rfcdate(mdate));
|
|
Send(newsmode, temp);
|
|
}
|
|
|
|
if ((p = hdr((char *)"Subject",msg)))
|
|
sprintf(temp, "Subject:%s", p);
|
|
else if ((p = hdr((char *)"RFC-Subject",kmsg)))
|
|
sprintf(temp, "Subject: %s", p);
|
|
else if ((p = hdr((char *)"Subject",kmsg)))
|
|
sprintf(temp, "Subject: %s", p);
|
|
else if ((p = hdr((char *)"X-PcBoard-SUBJECT",msg)))
|
|
sprintf(temp, "Subject:%s", p);
|
|
else if (subj && (strspn(subj," \t\n\r") != strlen(subj)))
|
|
sprintf(temp, "Subject: %s\n", subj);
|
|
else
|
|
sprintf(temp, "Subject: <none>\n");
|
|
Send(newsmode, temp);
|
|
|
|
if ((p=hdr((char *)"Message-ID",msg)))
|
|
sprintf(temp,"Message-ID:%s",p);
|
|
else if ((p=hdr((char *)"RFC-Message-ID",kmsg)))
|
|
sprintf(temp,"Message-ID: %s",p);
|
|
else if ((p=hdr((char *)"Message-ID",kmsg)))
|
|
sprintf(temp,"Message-ID: %s",p);
|
|
else if ((p=hdr((char *)"RFCID",kmsg))) {
|
|
if ((p[0]=='<')) {
|
|
/* "^aRFCID: <local@machine>" */
|
|
if ((p[strlen(p)-2]=='>')) {
|
|
sprintf(temp,"Message-ID: %s",p);
|
|
/* "^aRFCID: <local@machine" */
|
|
/* I saw it on some IntToss gated articles
|
|
* it seems to be a bug on the program or something
|
|
* like that, because in the majority of IntToss gated
|
|
* articles it is "^aRFCID: local@machine"
|
|
*/
|
|
} else {
|
|
p[strlen(p)-1]='\0';
|
|
sprintf(temp,"Message-ID: %s>\n",p);
|
|
}
|
|
/* "^aRFCID: local@machine" */
|
|
} else {
|
|
p[strlen(p)-1]='\0';
|
|
sprintf(temp,"Message-ID: <%s>\n",p);
|
|
}
|
|
} else if ((p=hdr((char *)"ORIGID",kmsg))) {
|
|
sprintf(temp,"Message-ID: %s",p);
|
|
} else if ((p = hdr((char *)"MSGID",kmsg))) {
|
|
q = rfcmsgid(p, bestaka);
|
|
sprintf(temp,"Message-ID: %s\n", q);
|
|
free(q);
|
|
} else {
|
|
sprintf(temp,"Message-ID: <%lu@%s.ftn>\n", mdate^(subj?str_crc32(subj):0L), ascinode(f,0x1f));
|
|
}
|
|
Send(newsmode, temp);
|
|
|
|
if (newsmode) {
|
|
if ((p=hdr((char *)"References",msg))) {
|
|
sprintf(temp,"References:%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-References",kmsg))) {
|
|
sprintf(temp,"References: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"References",kmsg))) {
|
|
sprintf(temp,"References: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"ORIGREF",kmsg))) {
|
|
sprintf(temp,"References: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"REPLY",kmsg))) {
|
|
q = rfcmsgid(p, bestaka);
|
|
sprintf(temp,"References: %s\n", q);
|
|
Send(newsmode, temp);
|
|
free(q);
|
|
}
|
|
} else {
|
|
if ((p=hdr((char *)"In-Reply-To",msg))) {
|
|
sprintf(temp,"In-Reply-To:%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-In-Reply-To",kmsg))) {
|
|
sprintf(temp,"In-Reply-To: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"REPLY",kmsg))) {
|
|
q = rfcmsgid(p,bestaka);
|
|
sprintf(temp,"In-Reply-To: %s\n", q);
|
|
Send(newsmode, temp);
|
|
free(q);
|
|
}
|
|
}
|
|
|
|
if ((p=hdr((char *)"Organization",msg))) {
|
|
sprintf(temp,"Organization:%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"Organisation",msg))) {
|
|
sprintf(temp,"Organization:%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-Organization",kmsg))) {
|
|
sprintf(temp,"Organization: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-Organisation",kmsg))) {
|
|
sprintf(temp,"Organization: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"Organization",kmsg))) {
|
|
sprintf(temp,"Organization: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"Organisation",kmsg))) {
|
|
sprintf(temp,"Organization: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if (origline) {
|
|
sprintf(temp,"Organization: %s\n",origline);
|
|
Send(newsmode, temp);
|
|
}
|
|
|
|
if ((p=hdr((char *)"Supersedes",msg))) {
|
|
sprintf(temp,"Supersedes:%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-Supersedes",kmsg))) {
|
|
sprintf(temp,"Supersedes: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"Supersedes",kmsg))) {
|
|
sprintf(temp,"Supersedes: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"ACUPDATE",kmsg)) && (strstr(p,"MODIFY"))) {
|
|
q = rfcmsgid(p+8,bestaka);
|
|
sprintf(temp,"Supersedes: %s\n", q);
|
|
Send(newsmode, temp);
|
|
free(q);
|
|
}
|
|
|
|
if (CFG.allowcontrol) {
|
|
if ((p=hdr((char *)"Control",msg))) {
|
|
sprintf(temp,"Control:%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-Control",kmsg))) {
|
|
sprintf(temp,"Control: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"Control",kmsg))) {
|
|
sprintf(temp,"Control: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"ACUPDATE",kmsg)) && (strstr(p,"DELETE"))) {
|
|
q = rfcmsgid(p+8,bestaka);
|
|
sprintf(temp,"Control: cancel %s\n", q);
|
|
Send(newsmode, temp);
|
|
free(q);
|
|
}
|
|
}
|
|
|
|
if ((p=hdr((char *)"Mime-Version",msg))) {
|
|
sprintf(temp,(char *)"Mime-Version:%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-Mime-Version",kmsg))) {
|
|
sprintf(temp,(char *)"Mime-Version: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"Mime-Version",kmsg))) {
|
|
sprintf(temp,(char *)"Mime-Version: %s",p);
|
|
Send(newsmode, temp);
|
|
}
|
|
|
|
/*
|
|
* We have setup translation, send the right charset name
|
|
*/
|
|
if ((p=hdr((char *)"Content-Type",msg))) {
|
|
sprintf(temp, "Content-Type: text/plain; charset=%s\n", getrfcchrs(msgs.Charset));
|
|
// sprintf(temp,"Content-Type:%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-Content-Type",kmsg))) {
|
|
sprintf(temp, "Content-Type: text/plain; charset=%s\n", getrfcchrs(msgs.Charset));
|
|
// sprintf(temp,"Content-Type: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"Content-Type",kmsg))) {
|
|
sprintf(temp, "Content-Type: text/plain; charset=%s\n", getrfcchrs(msgs.Charset));
|
|
// sprintf(temp,"Content-Type: %s",p);
|
|
Send(newsmode, temp);
|
|
}
|
|
|
|
if ((p=hdr((char *)"Content-Length",msg))) {
|
|
sprintf(temp,"Content-Length%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-Content-Length",kmsg))) {
|
|
sprintf(temp,"Content-Length: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"Content-Length",kmsg))) {
|
|
sprintf(temp,"Content-Length: %s",p);
|
|
Send(newsmode, temp);
|
|
}
|
|
|
|
if ((p=hdr((char *)"Content-Transfer-Encoding",msg))) {
|
|
sprintf(temp,"Content-Transfer-Encoding:%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-Content-Transfer-Encoding",kmsg))) {
|
|
sprintf(temp,"Content-Transfer-Encoding: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"Content-Transfer-Encoding",kmsg))) {
|
|
sprintf(temp,"Content-Transfer-Encoding: %s",p);
|
|
Send(newsmode, temp);
|
|
}
|
|
|
|
if (newsmode) {
|
|
if ((p=hdr((char *)"X-Newsreader",msg))) {
|
|
sprintf(temp,"X-Newsreader: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-X-Newsreader",kmsg))) {
|
|
sprintf(temp,"X-Newsreader: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"X-Newsreader",kmsg))) {
|
|
sprintf(temp,"X-Newsreader: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"PID",kmsg))) {
|
|
sprintf(temp,"X-Newsreader: %s",p);
|
|
Send(newsmode, temp);
|
|
}
|
|
} else {
|
|
if ((p=hdr((char *)"X-Mailer",msg))) {
|
|
sprintf(temp,"X-Mailer:%s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"RFC-X-Mailer",kmsg))) {
|
|
sprintf(temp,"X-Mailer: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"X-Mailer",kmsg))) {
|
|
sprintf(temp,"X-Mailer: %s",p);
|
|
Send(newsmode, temp);
|
|
} else if ((p=hdr((char *)"PID",kmsg))) {
|
|
sprintf(temp,"X-Mailer: %s",p);
|
|
Send(newsmode, temp);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Convert some ftn kludges to rfc. We should not have these but
|
|
* GoldED posts news with plain ftn kludges as rfc headers.
|
|
*/
|
|
if ((p = hdr((char *)"CHRS", msg))) {
|
|
sprintf(temp, "X-FTN-CHRS:%s", p);
|
|
Send(newsmode, temp);
|
|
}
|
|
if ((p = hdr((char *)"MSGID", msg))) {
|
|
sprintf(temp, "X-FTN-MSGID:%s", p);
|
|
Send(newsmode, temp);
|
|
}
|
|
if ((p = hdr((char *)"PID", msg))) {
|
|
sprintf(temp, "X-FTN-PID:%s", p);
|
|
Send(newsmode, temp);
|
|
}
|
|
if ((p = hdr((char *)"TZUTC", msg))) {
|
|
sprintf(temp, "X-FTN-TZUTC:%s", p);
|
|
Send(newsmode, temp);
|
|
}
|
|
|
|
Syslog('m', "=== starting qmsg loop");
|
|
for (qmsg = msg; qmsg; qmsg = qmsg->next) {
|
|
if (strcasecmp(qmsg->key,"CHRS") &&
|
|
strcasecmp(qmsg->key,"MSGID") &&
|
|
strcasecmp(qmsg->key,"PID") &&
|
|
strcasecmp(qmsg->key,"TZUTC") &&
|
|
strcasecmp(qmsg->key,"X-Body-Start") &&
|
|
strcasecmp(qmsg->key,"X-PcBoard-FROM") &&
|
|
strcasecmp(qmsg->key,"X-PcBoard-SUBJECT") &&
|
|
strcasecmp(qmsg->key,"X-PcBoard-PACKOUT") &&
|
|
(strcasecmp(qmsg->key,"Control") || !CFG.allowcontrol) &&
|
|
strcasecmp(qmsg->key,"Supersedes") &&
|
|
strcasecmp(qmsg->key,"Mime-Version") &&
|
|
strcasecmp(qmsg->key,"Content-Type") &&
|
|
strcasecmp(qmsg->key,"Content-Length") &&
|
|
strcasecmp(qmsg->key,"Content-Transfer-Encoding") &&
|
|
strcasecmp(qmsg->key,"Lines") &&
|
|
strcasecmp(qmsg->key,"Path") &&
|
|
strcasecmp(qmsg->key,"Received") &&
|
|
strcasecmp(qmsg->key,"From") &&
|
|
strcasecmp(qmsg->key,"To") &&
|
|
strcasecmp(qmsg->key,"Comment-To") &&
|
|
strcasecmp(qmsg->key,"X-Comment-To") &&
|
|
strcasecmp(qmsg->key,"Date") &&
|
|
strcasecmp(qmsg->key,"Subject") &&
|
|
strcasecmp(qmsg->key,"Reply-To") &&
|
|
strcasecmp(qmsg->key,"In-Reply-To") &&
|
|
strcasecmp(qmsg->key,"References") &&
|
|
strcasecmp(qmsg->key,"Organization") &&
|
|
strcasecmp(qmsg->key,"Organisation") &&
|
|
strcasecmp(qmsg->key,"X-Mailer") &&
|
|
strcasecmp(qmsg->key,"X-Newsreader") &&
|
|
(strcasecmp(qmsg->key,"Newsgroups") || !newsmode) &&
|
|
strcasecmp(qmsg->key,"Apparently-To") &&
|
|
strcasecmp(qmsg->key,"Distribution") &&
|
|
strcasecmp(qmsg->key,"Approved") &&
|
|
strcasecmp(qmsg->key,"Message-ID")) {
|
|
sprintf(temp,"%s:%s",qmsg->key,qmsg->val);
|
|
Send(newsmode, temp);
|
|
}
|
|
}
|
|
Syslog('m', "=== ending qmsg loop");
|
|
|
|
if ((p=compose_flags(flags,hdr((char *)"FLAGS",kmsg)))) {
|
|
sprintf(temp,"X-FTN-FLAGS:%s\n",p);
|
|
Send(newsmode, temp);
|
|
free(p);
|
|
}
|
|
|
|
Syslog('m', "=== starting qmsg loop 2");
|
|
for (qmsg = kmsg; qmsg; qmsg = qmsg->next) {
|
|
if (strcasecmp(qmsg->key,"INTL") &&
|
|
strcasecmp(qmsg->key,"FMPT") &&
|
|
strcasecmp(qmsg->key,"TOPT") &&
|
|
strcasecmp(qmsg->key,"FLAGS") &&
|
|
strcasecmp(qmsg->key,"CHARSET") &&
|
|
strcasecmp(qmsg->key,"CHRS") &&
|
|
strcasecmp(qmsg->key,"CODEPAGE") &&
|
|
strcasecmp(qmsg->key,"ORIGCHRS") &&
|
|
/*
|
|
* RFC: is used by fidogate to tell how completly RFC headers were
|
|
* gated (0=no headers at all; 1=some headers; 2=all headers)
|
|
*/
|
|
strcasecmp(qmsg->key,"RFC") &&
|
|
strcasecmp(qmsg->key,"RFCID") &&
|
|
strcasecmp(qmsg->key,"ORIGID") &&
|
|
strcasecmp(qmsg->key,"ORIGREF") &&
|
|
strcasecmp(qmsg->key,"X-GATEWAY") &&
|
|
strcasecmp(qmsg->key,"Lines") &&
|
|
/* strcmp(qmsg->key,"Path") && */
|
|
strcasecmp(qmsg->key,"PATH") &&
|
|
strcasecmp(qmsg->key,"Received") &&
|
|
strcasecmp(qmsg->key,"From") &&
|
|
strcasecmp(qmsg->key,"To") &&
|
|
strcasecmp(qmsg->key,"Comment-To") &&
|
|
strcasecmp(qmsg->key,"X-Comment-To") &&
|
|
strcasecmp(qmsg->key,"Date") &&
|
|
strcasecmp(qmsg->key,"Subject") &&
|
|
strcasecmp(qmsg->key,"Reply-To") &&
|
|
strcasecmp(qmsg->key,"In-Reply-To") &&
|
|
strcasecmp(qmsg->key,"References") &&
|
|
strcasecmp(qmsg->key,"Organization") &&
|
|
strcasecmp(qmsg->key,"Organisation") &&
|
|
strcasecmp(qmsg->key,"X-Mailer") &&
|
|
strcasecmp(qmsg->key,"X-Newsreader") &&
|
|
(strcasecmp(qmsg->key,"Newsgroups") || !newsmode) &&
|
|
strcasecmp(qmsg->key,"Apparently-To") &&
|
|
strcasecmp(qmsg->key,"Message-ID") &&
|
|
strcasecmp(qmsg->key,"Mime-Version") &&
|
|
strcasecmp(qmsg->key,"Content-Type") &&
|
|
strcasecmp(qmsg->key,"Content-Lenght") &&
|
|
strcasecmp(qmsg->key,"Content-Transfer-Encoding") &&
|
|
(strcasecmp(qmsg->key,"RFC-Control") || !CFG.allowcontrol) &&
|
|
strcasecmp(qmsg->key,"RFC-Supersedes") &&
|
|
strcasecmp(qmsg->key,"RFC-Mime-Version") &&
|
|
strcasecmp(qmsg->key,"RFC-Content-Type") &&
|
|
strcasecmp(qmsg->key,"RFC-Content-Lenght") &&
|
|
strcasecmp(qmsg->key,"RFC-Content-Transfer-Encoding") &&
|
|
strcasecmp(qmsg->key,"RFC-Lines") &&
|
|
strcasecmp(qmsg->key,"RFC-Path") &&
|
|
strcasecmp(qmsg->key,"RFC-Received") &&
|
|
strcasecmp(qmsg->key,"RFC-From") &&
|
|
strcasecmp(qmsg->key,"RFC-To") &&
|
|
strcasecmp(qmsg->key,"RFC-Comment-To") &&
|
|
strcasecmp(qmsg->key,"RFC-X-Comment-To") &&
|
|
strcasecmp(qmsg->key,"RFC-Date") &&
|
|
strcasecmp(qmsg->key,"RFC-Subject") &&
|
|
strcasecmp(qmsg->key,"RFC-Reply-To") &&
|
|
strcasecmp(qmsg->key,"RFC-In-Reply-To") &&
|
|
strcasecmp(qmsg->key,"RFC-References") &&
|
|
strcasecmp(qmsg->key,"RFC-Organization") &&
|
|
strcasecmp(qmsg->key,"RFC-X-Mailer") &&
|
|
strcasecmp(qmsg->key,"RFC-X-Newsreader") &&
|
|
(strcasecmp(qmsg->key,"RFC-Newsgroups") || !newsmode) &&
|
|
strcasecmp(qmsg->key,"RFC-Apparently-To") &&
|
|
strcasecmp(qmsg->key,"RFC-Distribution") &&
|
|
strcasecmp(qmsg->key,"RFC-Approved") &&
|
|
strcasecmp(qmsg->key,"RFC-Message-ID")) {
|
|
if (!strncmp(qmsg->key,"RFC-",4)) {
|
|
sprintf(temp,"%s: %s",qmsg->key+4,qmsg->val);
|
|
Send(newsmode, temp);
|
|
} else if ((!strncasecmp(qmsg->key,"X-",2)) || (!strncasecmp(qmsg->key,"NNTP-",5))) {
|
|
sprintf(temp,"%s: %s",qmsg->key,qmsg->val);
|
|
Send(newsmode, temp);
|
|
} else if ((!strncasecmp(qmsg->key,"ZC-",3))) {
|
|
sprintf(temp,"X-%s: %s",qmsg->key,qmsg->val);
|
|
Send(newsmode, temp);
|
|
} else if ((!strcasecmp(qmsg->key,"Origin")) || (!strcasecmp(qmsg->key,"MOOD"))) {
|
|
sprintf(temp,"X-FTN-%s: %s",qmsg->key,qmsg->val);
|
|
Send(newsmode, temp);
|
|
} else {
|
|
sprintf(temp,"X-FTN-%s: %s",qmsg->key,qmsg->val);
|
|
Send(newsmode, temp);
|
|
}
|
|
}
|
|
}
|
|
Syslog('m', "=== ending qmsg loop 2");
|
|
|
|
if (newsmode) {
|
|
fa_list *tmpl,*ptl=NULL;
|
|
char sbe[16];
|
|
int seenlen=0,oldnet;
|
|
|
|
for (qmsg = kmsg; qmsg; qmsg = qmsg->next)
|
|
if (!strcmp(qmsg->key, "PATH")) {
|
|
fill_path(&ptl, qmsg->val);
|
|
}
|
|
|
|
uniq_list(&ptl);
|
|
|
|
/*
|
|
* ensure it will not match for the first entry
|
|
*/
|
|
oldnet = ptl->addr->net-1;
|
|
q = xstrcpy((char*)"X-FTN-PATH:");
|
|
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;
|
|
sprintf(temp, "%s\n", q);
|
|
Send(newsmode, temp);
|
|
free(q);
|
|
q = xstrcpy((char *)"X-FTN-PATH:");
|
|
sprintf(sbe," %u/%u",tmpl->addr->net, tmpl->addr->node);
|
|
seenlen=strlen(sbe);
|
|
}
|
|
q = xstrcat(q, sbe);
|
|
}
|
|
sprintf(temp,"%s\n", q);
|
|
Send(newsmode, temp);
|
|
free(q);
|
|
tidy_falist(&ptl);
|
|
|
|
if ((hdr((char *)"X-FTN-SPTH", msg))) {
|
|
sprintf(temp,"X-FTN-SPTH: %s\n", ascfnode(bestaka,0x1f));
|
|
Send(newsmode, temp);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Search past RFC headers.
|
|
*/
|
|
while (fgets(buf,sizeof(buf)-1,fp)) {
|
|
if ((strlen(buf) == 1) && (buf[0] == '\n')) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Send the message body
|
|
*/
|
|
pass=1;
|
|
count = lines = 0;
|
|
first = TRUE;
|
|
|
|
Syslog('m', "Start sending message body");
|
|
while (fgets(buf,sizeof(buf)-1,fp) && pass) {
|
|
if (first) {
|
|
p = xstrcpy((char *)"\n");
|
|
Send(newsmode, p);
|
|
free(p);
|
|
first = FALSE;
|
|
|
|
/* FIXME: Maybe scan now for repeating headers and drop them as they will appear in the message text */
|
|
|
|
if ((p=hdr((char *)"X-Body-Start",msg))) {
|
|
lines++;
|
|
q = xstrcpy(p);
|
|
Send(newsmode, q);
|
|
free(q);
|
|
}
|
|
}
|
|
|
|
if (ftell(fp) > endmsg_off) {
|
|
Syslog('m', "line \"%s\" past message end %ld %ld", buf,(long)endmsg_off, ftell(fp));
|
|
pass=0;
|
|
}
|
|
if (pass) {
|
|
p=buf;
|
|
b=NULL;
|
|
while ((c=*p++)) {
|
|
switch (c) {
|
|
case ' ': b=p-1; break;
|
|
case '\n': b=NULL; count=0; lines++; break;
|
|
}
|
|
if ((count++ > BOUNDARY) /* && (!pgpsigned) */ ) {
|
|
if (b) {
|
|
*b++='\n'; // Replace space.
|
|
p = b + 1;
|
|
b=NULL;
|
|
lines++;
|
|
count=0;
|
|
}
|
|
}
|
|
}
|
|
if ((strncmp(buf, ".\r\n", 3)) && (strncmp(buf, ".\n", 2)))
|
|
q = xstrcpy(buf);
|
|
else
|
|
q = xstrcpy((char *)" .\n");
|
|
Send(newsmode, q);
|
|
free(q);
|
|
}
|
|
}
|
|
Syslog('m', "End sending message body");
|
|
|
|
if (charset)
|
|
free(charset);
|
|
|
|
tidyrfc(msg);
|
|
fclose(fp);
|
|
tidyrfc(kmsg);
|
|
|
|
if (!newsmode) {
|
|
result = postemail(nfp, MailFrom, MailTo);
|
|
fclose(nfp);
|
|
} else {
|
|
news_in++;
|
|
/*
|
|
* The newsfile stays open and will be closed later after processing
|
|
* all echomail.
|
|
*/
|
|
fprintf(nfp, ".\n");
|
|
}
|
|
|
|
if (newsgroup)
|
|
free(newsgroup);
|
|
rbuf = NULL;
|
|
free(temp);
|
|
return result;
|
|
}
|
|
|
|
|