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/postecho.c

572 lines
15 KiB
C
Raw Normal View History

2001-08-25 20:32:59 +00:00
/*****************************************************************************
*
2001-12-13 19:34:18 +00:00
* $Id$
2001-08-25 20:32:59 +00:00
* Purpose ...............: Post echomail message.
*
*****************************************************************************
2005-08-28 12:35:18 +00:00
* Copyright (C) 1997-2005
2001-08-25 20:32:59 +00:00
*
* 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
2003-08-15 20:05:34 +00:00
* Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
2001-08-25 20:32:59 +00:00
*****************************************************************************/
2002-06-30 12:48:44 +00:00
#include "../config.h"
2004-02-21 17:22:00 +00:00
#include "../lib/mbselib.h"
2002-01-07 19:16:03 +00:00
#include "../lib/users.h"
2001-08-25 20:32:59 +00:00
#include "../lib/msg.h"
#include "../lib/msgtext.h"
2004-02-21 17:22:00 +00:00
#include "../lib/mbsedb.h"
2001-08-25 20:32:59 +00:00
#include "ftn2rfc.h"
#include "postecho.h"
#include "storeecho.h"
#include "addpkt.h"
#include "rollover.h"
#include "qualify.h"
2001-08-25 20:32:59 +00:00
/*
* External declarations
*/
extern int do_quiet; /* No tty output */
extern int do_unsec; /* Toss unsecure */
extern int check_dupe; /* Check dupes */
extern time_t t_start; /* Reference time */
extern int echo_in; /* Echomail processed */
extern int echo_out; /* Echomail forwarded */
extern int echo_bad; /* Bad echomail */
#define MAXPATH 73
#define MAXSEEN 70
2002-06-20 20:12:00 +00:00
int EchoOut(fidoaddr, char *, char *, char *, FILE *, int, int, time_t);
2001-08-25 20:32:59 +00:00
/*
* Add echomail mesage to the queue.
*/
int EchoOut(fidoaddr aka, char *toname, char *fromname, char *subj, FILE *fp, int flags, int cost, time_t date)
{
char *buf, ext[4];
2002-06-20 20:12:00 +00:00
FILE *qp;
faddr *From, *To;
int rc;
/*
* Pack flavor for echomail packets.
*/
memset(&ext, 0, sizeof(ext));
if (nodes.PackNetmail)
2005-08-28 12:35:18 +00:00
snprintf(ext, 3, (char *)"qqq");
else if (nodes.Crash)
2005-08-28 12:35:18 +00:00
snprintf(ext, 3, (char *)"ccc");
else if (nodes.Hold)
2005-08-28 12:35:18 +00:00
snprintf(ext, 3, (char *)"hhh");
else
2005-08-28 12:35:18 +00:00
snprintf(ext, 3, (char *)"nnn");
if ((qp = OpenPkt(msgs.Aka, aka, (char *)ext)) == NULL) {
2002-06-20 20:12:00 +00:00
WriteError("EchoOut(): OpenPkt failed");
return 1;
}
From = fido2faddr(msgs.Aka);
To = fido2faddr(aka);
rc = AddMsgHdr(qp, From, To, flags, cost, date, toname, fromname, subj);
tidy_faddr(To);
tidy_faddr(From);
if (rc) {
WriteError("EchoOut(): AddMsgHdr failed");
return 1;
}
rewind(fp);
buf = calloc(MAX_LINE_LENGTH +1, sizeof(char));
2002-06-20 20:12:00 +00:00
while ((fgets(buf, MAX_LINE_LENGTH, fp)) != NULL) {
2002-06-20 20:12:00 +00:00
Striplf(buf);
fprintf(qp, "%s\r", buf);
}
free(buf);
putc(0, qp);
fsync(fileno(qp));
fclose(qp);
return 0;
2001-08-25 20:32:59 +00:00
}
/*
* Post echomail message, forward if needed.
* pkt_from, from, to, subj, orig, mdate, flags, cost, file
* The msgs record must be in memory.
*
* 1 - Cannot open message base.
* 4 - Rejected echomail message.
*
* For echomail, the crc32 is calculated over the ^AREA kludge, subject,
* message date, origin line, message id.
*/
int postecho(faddr *p_from, faddr *f, faddr *t, char *orig, char *subj, time_t mdate, int flags,
int cost, FILE *fp, int tonews, int isbad)
2001-08-25 20:32:59 +00:00
{
2002-12-11 22:21:36 +00:00
char *buf, *msgid = NULL, *reply = NULL, *p, *q, sbe[16];
2002-12-11 18:26:05 +00:00
int First = TRUE, rc = 0, i, kludges = TRUE, dupe = FALSE, bad = TRUE, seenlen, oldnet;
2003-02-12 20:20:59 +00:00
faddr *Faddr;
2002-06-20 20:12:00 +00:00
unsigned long crc;
sysconnect Link;
fa_list *sbl = NULL, *ptl = NULL, *tmpl;
qualify *qal = NULL, *tmpq;
FILE *nfp, *qp;
2002-12-11 22:21:36 +00:00
time_t ddate;
2002-06-20 20:12:00 +00:00
memset(&Link, 0, sizeof(Link));
crc = 0xffffffff;
echo_in++;
if (isbad)
Syslog('m', "postecho isbad=%d", isbad);
2002-06-20 20:12:00 +00:00
/*
* p_from is set for tossed echomail, it is NULL for local posted echomail and gated news.
*/
if (p_from) {
while (GetMsgSystem(&Link, First)) {
First = FALSE;
if ((p_from->zone == Link.aka.zone) && (p_from->net == Link.aka.net) && (p_from->node == Link.aka.node)) {
2001-08-25 20:32:59 +00:00
bad = FALSE;
2002-06-20 20:12:00 +00:00
break;
}
2001-08-25 20:32:59 +00:00
}
/*
* Echomail for unknow area was passed, make sure we pass the next tests
*/
if (isbad == 6) {
bad = FALSE;
Link.receivefrom = TRUE;
}
2002-06-20 20:12:00 +00:00
if (bad && (msgs.UnSecure || do_unsec)) {
bad = FALSE;
memset(&Link, 0, sizeof(Link));
2003-02-05 20:56:05 +00:00
Syslog('!', "Warning, unsecure echomail from %s accepted in area %s", ascfnode(p_from, 0x1f), msgs.Tag);
2001-08-25 20:32:59 +00:00
}
2002-06-20 20:12:00 +00:00
if (bad) {
Syslog('+', "Node %s not connected to area %s", ascfnode(p_from, 0x1f), msgs.Tag);
bad = FALSE;
Link.receivefrom = TRUE;
isbad = 7; /* Force to goto badboard */
2002-06-20 20:12:00 +00:00
}
if (Link.cutoff && !bad) {
Syslog('+', "Echomail from %s in %s refused, cutoff", ascfnode(p_from, 0x1f), msgs.Tag);
bad = TRUE;
echo_bad++;
return 4;
}
if (!Link.receivefrom && !bad) {
Syslog('+', "Echomail from %s in %s refused, read only", ascfnode(p_from, 0x1f), msgs.Tag);
bad = TRUE;
echo_bad++;
return 4;
}
} else {
2001-08-25 20:32:59 +00:00
/*
2002-06-20 20:12:00 +00:00
* Fake the zone entry to be our own zone, this prevents
* zonegate behaviour. It's also not a bad message yet.
2001-08-25 20:32:59 +00:00
*/
2002-06-20 20:12:00 +00:00
Link.aka.zone = msgs.Aka.zone;
bad = FALSE;
}
if (CFG.toss_old && ((t_start - mdate) / 86400) > CFG.toss_old) {
Syslog('+', "Rejecting msg: too old, %s", rfcdate(mdate));
bad = TRUE;
echo_bad++;
return 4;
}
/*
* Read the message for kludges we need.
*/
buf = calloc(MAX_LINE_LENGTH +1, sizeof(char));
2002-06-20 20:12:00 +00:00
First = TRUE;
rewind(fp);
while ((fgets(buf, MAX_LINE_LENGTH, fp)) != NULL) {
2002-06-20 20:12:00 +00:00
Striplf(buf);
if (First && (!strncmp(buf, "AREA:", 5))) {
crc = upd_crc32(buf, crc, strlen(buf));
First = FALSE;
2001-08-25 20:32:59 +00:00
}
2003-01-03 13:13:13 +00:00
if (!strncmp(buf, "\001MSGID: ", 8)) {
2002-06-20 20:12:00 +00:00
msgid = xstrcpy(buf + 8);
2003-01-03 13:13:13 +00:00
}
2002-06-20 20:12:00 +00:00
if (!strncmp(buf, "\001REPLY: ", 8))
reply = xstrcpy(buf + 8);
if (!strncmp(buf, "SEEN-BY:", 8)) {
2003-02-12 20:20:59 +00:00
p = xstrcpy(buf + 9);
fill_list(&sbl, p, NULL);
free(p);
2001-08-25 20:32:59 +00:00
}
2002-06-20 20:12:00 +00:00
if (!strncmp(buf, "\001PATH:", 6)) {
p = xstrcpy(buf + 7);
fill_path(&ptl, p);
free(p);
}
} /* end of checking kludges */
/*
* Further dupe checking.
*/
crc = upd_crc32(subj, crc, strlen(subj));
if (orig == NULL)
Syslog('!', "No origin line found");
else
crc = upd_crc32(orig, crc, strlen(orig));
2002-12-11 18:26:05 +00:00
/*
* Some tossers don't bother the seconds in the message, also some
* rescanning software changes the seconds of a message. Do the
* timestamp check without the seconds.
*/
2002-12-11 22:21:36 +00:00
ddate = mdate - (mdate % 60);
crc = upd_crc32((char *)&ddate, crc, sizeof(ddate));
2002-12-11 18:26:05 +00:00
2002-06-20 20:12:00 +00:00
if (msgid != NULL) {
crc = upd_crc32(msgid, crc, strlen(msgid));
} else {
if (check_dupe && !isbad) {
2002-06-20 20:12:00 +00:00
/*
* If a MSGID is missing it is possible that dupes from some offline
* readers slip through because these readers use the same date for
* each message. In this case the message text is included in the
* dupecheck. Redy Rodriguez.
*/
rewind(fp);
while ((fgets(buf, MAX_LINE_LENGTH, fp)) != NULL) {
2002-06-20 20:12:00 +00:00
Striplf(buf);
if (strncmp(buf, "---", 3) == 0)
break;
if ((strncmp(buf, "\001", 1) != 0 ) && (strncmp(buf,"AREA:",5) != 0 ))
crc = upd_crc32(buf, crc , strlen(buf));
}
}
}
if (check_dupe && !isbad)
2002-06-20 20:12:00 +00:00
dupe = CheckDupe(crc, D_ECHOMAIL, CFG.toss_dupes);
else
dupe = FALSE;
if (!dupe && !msgs.UnSecure && !do_unsec && !isbad) {
2001-08-25 20:32:59 +00:00
/*
2002-06-20 20:12:00 +00:00
* Check if the message is for us. Don't check point address,
* echomail messages don't have point destination set.
2001-08-25 20:32:59 +00:00
*/
2002-06-20 20:12:00 +00:00
if ((msgs.Aka.zone != t->zone) || (msgs.Aka.net != t->net) || (msgs.Aka.node != t->node)) {
bad = TRUE;
/*
* If we are a hub or host and have all our echomail
* connected to the hub/host aka, echomail from points
* under a nodenumber aka isn't accepted. The match
* must be further tested.
*/
if ((msgs.Aka.zone == t->zone) && (msgs.Aka.net == t->net)) {
2001-08-25 20:32:59 +00:00
for (i = 0; i < 40; i++) {
2002-06-20 20:12:00 +00:00
if ((CFG.akavalid[i]) && (CFG.aka[i].zone == t->zone) &&
(CFG.aka[i].net == t->net) && (CFG.aka[i].node == t->node))
bad = FALSE; /* Undo the result */
2001-08-25 20:32:59 +00:00
}
2002-06-20 20:12:00 +00:00
}
2001-08-25 20:32:59 +00:00
}
2002-06-20 20:12:00 +00:00
if (bad) {
echo_bad++;
WriteError("Msg in %s not for us (%s) but for %s", msgs.Tag, aka2str(msgs.Aka), ascfnode(t,0x1f));
free(buf);
if (msgid)
free(msgid);
if (reply)
free(reply);
return 4;
}
}
if (isbad) {
/*
* If the isbad was passed, this is echomail with an error that maybe
* later can be retossed from the bad board. Store it as original as
* possible.
*/
Syslog('m', "storeecho to bad isbad=%d", isbad);
rc = storeecho(f, t, mdate, flags, subj, msgid, reply, TRUE, FALSE, fp);
free(buf);
if (msgid)
free(msgid);
if (reply)
free(reply);
return rc;
}
2002-06-20 20:12:00 +00:00
/*
* The echomail message is accepted for post/forward/gate
*/
if (!dupe && !isbad) {
2002-06-20 20:12:00 +00:00
if (msgs.Aka.zone != Link.aka.zone) {
/*
* If it is a zonegated echomailmessage the SEEN-BY lines
* are stripped off including that of the other zone's
* gate. Add the gate's aka to the SEEN-BY
*/
Syslog('m', "Gated echomail, clean SB");
tidy_falist(&sbl);
2005-08-28 12:35:18 +00:00
snprintf(sbe, 15, "%u/%u", Link.aka.net, Link.aka.node);
2002-06-20 20:12:00 +00:00
Syslog('m', "Add gate SB %s", sbe);
fill_list(&sbl, sbe, NULL);
2001-08-25 20:32:59 +00:00
}
/*
2002-06-20 20:12:00 +00:00
* Add more aka's to SEENBY if in the same zone as our system.
* When ready filter dupe's, there is at least one.
2001-08-25 20:32:59 +00:00
*/
2002-06-20 20:12:00 +00:00
for (i = 0; i < 40; i++) {
if (CFG.akavalid[i] && (msgs.Aka.zone == CFG.aka[i].zone) && (CFG.aka[i].point == 0) &&
!((msgs.Aka.net == CFG.aka[i].net) && (msgs.Aka.node == CFG.aka[i].node))) {
2005-08-28 12:35:18 +00:00
snprintf(sbe, 15, "%u/%u", CFG.aka[i].net, CFG.aka[i].node);
2002-06-20 20:12:00 +00:00
fill_list(&sbl, sbe, NULL);
}
2001-08-25 20:32:59 +00:00
}
uniq_list(&sbl);
2002-06-20 20:12:00 +00:00
}
/*
* Add our system to the path for later export.
*/
2005-08-28 12:35:18 +00:00
snprintf(sbe, 15, "%u/%u", msgs.Aka.net, msgs.Aka.node);
2002-06-20 20:12:00 +00:00
fill_path(&ptl, sbe);
uniq_list(&ptl); /* remove possible duplicate own aka */
/*
* Build a list of qualified systems to receive this message.
* Complete the SEEN-BY lines.
*/
First = TRUE;
while (GetMsgSystem(&Link, First)) {
First = FALSE;
if ((Link.aka.zone) && (Link.sendto) && (!Link.pause) && (!Link.cutoff)) {
2002-06-20 20:12:00 +00:00
Faddr = fido2faddr(Link.aka);
if (p_from == NULL) {
fill_qualify(&qal, Link.aka, FALSE, in_list(Faddr, &sbl, FALSE));
2002-06-20 20:12:00 +00:00
} else {
fill_qualify(&qal, Link.aka, ((p_from->zone == Link.aka.zone) &&
2002-06-20 20:12:00 +00:00
(p_from->net == Link.aka.net) && (p_from->node == Link.aka.node) &&
(p_from->point == Link.aka.point)), in_list(Faddr, &sbl, FALSE));
}
tidy_faddr(Faddr);
2001-08-25 20:32:59 +00:00
}
2002-06-20 20:12:00 +00:00
}
2001-08-25 20:32:59 +00:00
2002-06-20 20:12:00 +00:00
/*
* Add SEEN-BY for nodes qualified to receive this message.
* When ready, filter the dupes and sort the SEEN-BY entries.
*/
for (tmpq = qal; tmpq; tmpq = tmpq->next) {
if (tmpq->send) {
2005-08-28 12:35:18 +00:00
snprintf(sbe, 15, "%u/%u", tmpq->aka.net, tmpq->aka.node);
2002-06-20 20:12:00 +00:00
fill_list(&sbl, sbe, NULL);
2001-08-25 20:32:59 +00:00
}
2002-06-20 20:12:00 +00:00
}
uniq_list(&sbl);
sort_list(&sbl);
/*
* Create a new tmpfile with a copy of the message
* without original PATH and SEENBY lines, add the
* new PATH and SEENBY lines.
*/
rewind(fp);
if ((nfp = tmpfile()) == NULL)
WriteError("$Unable to open tmpfile");
while ((fgets(buf, MAX_LINE_LENGTH, fp)) != NULL) {
2002-06-20 20:12:00 +00:00
Striplf(buf);
fprintf(nfp, "%s", buf);
2001-08-25 20:32:59 +00:00
/*
2002-06-20 20:12:00 +00:00
* Don't write SEEN-BY and PATH lines
2001-08-25 20:32:59 +00:00
*/
2002-06-20 20:12:00 +00:00
if (strncmp(buf, " * Origin:", 10) == 0)
break;
fprintf(nfp, "\n");
}
/*
* Now add new SEEN-BY and PATH lines
*/
seenlen = MAXSEEN + 1;
/*
* Ensure that 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)
2005-08-28 12:35:18 +00:00
snprintf(sbe, 15, " %u", tmpl->addr->node);
2002-06-20 20:12:00 +00:00
else
2005-08-28 12:35:18 +00:00
snprintf(sbe, 15, " %u/%u", tmpl->addr->net, tmpl->addr->node);
2002-06-20 20:12:00 +00:00
oldnet = tmpl->addr->net;
seenlen += strlen(sbe);
if (seenlen > MAXSEEN) {
seenlen = 0;
fprintf(nfp, "\nSEEN-BY:");
2005-08-28 12:35:18 +00:00
snprintf(sbe, 15, " %u/%u", tmpl->addr->net, tmpl->addr->node);
2002-06-20 20:12:00 +00:00
seenlen = strlen(sbe);
2001-08-25 20:32:59 +00:00
}
2002-06-20 20:12:00 +00:00
fprintf(nfp, "%s", sbe);
}
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)
2005-08-28 12:35:18 +00:00
snprintf(sbe, 15, " %u", tmpl->addr->node);
2002-06-20 20:12:00 +00:00
else
2005-08-28 12:35:18 +00:00
snprintf(sbe, 15, " %u/%u", tmpl->addr->net, tmpl->addr->node);
2002-06-20 20:12:00 +00:00
oldnet = tmpl->addr->net;
seenlen += strlen(sbe);
if (seenlen > MAXPATH) {
seenlen = 0;
fprintf(nfp, "\n\001PATH:");
2005-08-28 12:35:18 +00:00
snprintf(sbe, 15, " %u/%u", tmpl->addr->net, tmpl->addr->node);
2002-06-20 20:12:00 +00:00
seenlen = strlen(sbe);
2001-08-25 20:32:59 +00:00
}
2002-06-20 20:12:00 +00:00
fprintf(nfp, "%s", sbe);
}
fprintf(nfp, "\n");
fflush(nfp);
rewind(nfp);
2001-08-25 20:32:59 +00:00
2002-06-20 20:12:00 +00:00
/*
* Import this echomail, even if it's bad or a dupe.
*/
if ((rc = storeecho(f, t, mdate, flags, subj, msgid, reply, bad, dupe, nfp)) || bad || dupe) {
2001-08-25 20:32:59 +00:00
/*
2002-06-20 20:12:00 +00:00
* Store failed or it was bad or a dupe. Only log failed store.
2001-08-25 20:32:59 +00:00
*/
2002-06-20 20:12:00 +00:00
if (rc)
WriteError("Store echomail in JAM base failed");
2001-08-25 20:32:59 +00:00
tidy_falist(&sbl);
tidy_falist(&ptl);
tidy_qualify(&qal);
free(buf);
if (msgid)
2002-06-20 20:12:00 +00:00
free(msgid);
2001-08-25 20:32:59 +00:00
if (reply)
2002-06-20 20:12:00 +00:00
free(reply);
2002-12-11 18:26:05 +00:00
fclose(nfp);
2001-08-25 20:32:59 +00:00
return rc;
2002-06-20 20:12:00 +00:00
}
/*
* Forward to other links
*/
for (tmpq = qal; tmpq; tmpq = tmpq->next) {
if (tmpq->send) {
if (SearchNode(tmpq->aka)) {
StatAdd(&nodes.MailSent, 1L);
UpdateNode();
SearchNode(tmpq->aka);
echo_out++;
if (EchoOut(tmpq->aka, t->name, f->name, subj, nfp, flags, cost, mdate))
WriteError("Forward echomail to %s failed", aka2str(tmpq->aka));
} else {
WriteError("Forward echomail to %s failed, noderecord not found", aka2str(tmpq->aka));
2002-06-20 20:12:00 +00:00
}
}
}
2004-06-20 14:38:11 +00:00
#ifdef USE_NEWSGATE
/*
* Gate to newsserver
*/
if (strlen(msgs.Newsgroup) && tonews) {
#else
2002-06-20 20:12:00 +00:00
/*
2004-04-15 20:52:43 +00:00
* Gate to newsserver if this is a real newsgroup
2002-06-20 20:12:00 +00:00
*/
2004-04-15 20:52:43 +00:00
if (strlen(msgs.Newsgroup) && (msgs.Type == NEWS) && tonews) {
2004-06-20 14:38:11 +00:00
#endif
2002-06-20 20:12:00 +00:00
rewind(nfp);
qp = tmpfile();
while ((fgets(buf, MAX_LINE_LENGTH, nfp)) != NULL) {
2002-06-20 20:12:00 +00:00
Striplf(buf);
if (kludges && (buf[0] != '\001') && strncmp(buf, "AREA:", 5)) {
kludges = FALSE;
q = xstrcpy(Msg.From);
for (i = 0; i < strlen(q); i++)
if (q[i] == ' ')
q[i] = '_';
fprintf(qp, "From: %s@%s\n", q, ascinode(f, 0x1f));
fprintf(qp, "Subject: %s\n", Msg.Subject);
fprintf(qp, "To: %s\n", Msg.To);
free(q);
fprintf(qp, "\n");
}
fprintf(qp, "%s\n", buf);
}
rewind(qp);
ftn2rfc(f, t, subj, orig, mdate, flags, qp);
fclose(qp);
}
fclose(nfp);
/*
* Free memory used by SEEN-BY, ^APATH and Qualified lines.
*/
tidy_falist(&sbl);
tidy_falist(&ptl);
tidy_qualify(&qal);
if (rc < 0)
rc =-rc;
free(buf);
if (msgid)
free(msgid);
if (reply)
free(reply);
return rc;
2001-08-25 20:32:59 +00:00
}