/***************************************************************************** * * $Id$ * Purpose ...............: Toss a single *.pkt file * ***************************************************************************** * Copyright (C) 1997-2002 * * 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/users.h" #include "../lib/records.h" #include "../lib/common.h" #include "../lib/clcomm.h" #include "../lib/msg.h" #include "../lib/msgtext.h" #include "../lib/dbcfg.h" #include "../lib/dbnode.h" #include "../lib/dbmsgs.h" #include "../lib/dbdupe.h" #include "../lib/dbuser.h" #include "../lib/dbftn.h" #include "tosspkt.h" #include "postnetmail.h" #include "postecho.h" #include "rollover.h" /* * External declarations */ extern int do_quiet; extern int do_unsec; extern int check_dupe; extern int autocrea; extern time_t t_start; extern int most_debug; /* * Global variables */ int net_in = 0; /* Netmails received */ int net_imp = 0; /* Netmails imported */ int net_out = 0; /* Netmails forwarded */ int net_bad = 0; /* Bad netmails (tracking errors */ int echo_in = 0; /* Echomail received */ int echo_imp = 0; /* Echomail imported */ int echo_out = 0; /* Echomail forwarded */ int echo_bad = 0; /* Bad echomail */ int echo_dupe = 0; /* Dupe echomail */ int news_in = 0; /* News received */ int news_imp = 0; /* News imported */ int news_out = 0; /* News posted */ int news_bad = 0; /* Bad news */ int news_dupe = 0; /* Dupe articles */ int email_in = 0; /* Email received */ int email_imp = 0; /* Email imported */ int email_out = 0; /* Email forwarded */ int email_bad = 0; /* Bad email */ static int at_zero = 0; /* * Internal prototypes */ char *aread(char *, int, FILE *); int importmsg(faddr *, faddr *, faddr *, char *, char *, time_t, int, int, FILE *); void autocreate(char *, faddr *); char *aread(char *s, int count, FILE *fp) { int i,c,next; if (feof(fp)) return(NULL); if (s == NULL) return NULL; if (at_zero) { at_zero=0; return NULL; } for (i = 0,next = 1; (i < count-1) && next;) switch (c=getc(fp)) { case '\n': break; case '\r': s[i]='\n'; i++; next=0; break; case 0x8d: s[i]=' '; i++; break; case '\0': at_zero=1; next=0; break; default: s[i]=c; i++; break; } s[i]='\0'; return s; } /* * Import 1 message, forward if needed. * pkt_from, from, to, subj, orig, mdate, flags, cost, file * * 0 - All Seems Well. * 1 - Can't access messagebase. * 2 - Cannot open mareas.data * 3 - Echomail without Origin line. * 4 - Echomail from unknown node, disconnected node. * 5 - Locking error. * */ int importmsg(faddr *p_from, faddr *f, faddr *t, char *orig, char *subj, time_t mdate, int flags, int cost, FILE *fp) { char *buf, *marea = NULL; int echomail = FALSE, rc = 0, bad = FALSE, Known = FALSE, FirstLine; sysconnect Link; if (CFG.slow_util && do_quiet) usleep(1); memset(&Link, 0, sizeof(Link)); /* * Increase uplink's statistic counter. */ Link.aka.zone = p_from->zone; Link.aka.net = p_from->net; Link.aka.node = p_from->node; Link.aka.point = p_from->point; if (SearchNode(Link.aka)) { StatAdd(&nodes.MailRcvd, 1); UpdateNode(); SearchNode(Link.aka); Known = TRUE; } buf = calloc(2048, sizeof(char)); marea = NULL; /* * First read the message for kludges we need. */ rewind(fp); FirstLine = TRUE; while ((fgets(buf, 2048, fp)) != NULL) { Striplf(buf); /* * Check if message is echomail and if the areas exists. */ if (FirstLine && (!strncmp(buf, "AREA:", 5))) { marea = xstrcpy(tu(buf + 5)); if (orig == NULL) { Syslog('!', "Echomail without Origin line"); echo_bad++; echo_in++; bad = TRUE; free(buf); free(marea); return 3; } if (!SearchMsgs(marea)) { WriteError("Unknown echo area %s", marea); if (autocrea) { autocreate(marea, p_from); if (!SearchMsgs(marea)) { WriteError("Autocreate of area %s failed.", area); echo_bad++; echo_in++; bad = TRUE; free(marea); free(buf); return 4; } } else { echo_bad++; echo_in++; bad = TRUE; free(buf); free(marea); return 4; } } echomail = TRUE; free(marea); } if (*buf != '\001') FirstLine = FALSE; } /* end of checking kludges */ if (echomail) rc = postecho(p_from, f, t, orig, subj, mdate, flags, cost, fp, TRUE); else rc = postnetmail(fp, f, t, orig, subj, mdate, flags, TRUE); free(buf); return rc; } /* * Create echomail area if it doesn't excist and allowed. * Contributed by Redy Rodriguez. */ void autocreate(char *marea, faddr *p_from) { FILE *pMsgs; char temp[250]; int i; struct _sysconnect syscon; if (!SearchMsgs((char *)"DEFAULT")){ WriteError("Can't find DEFAULT area, can't autocreate:"); autocrea = FALSE; return; } sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT")); if ((pMsgs = fopen(temp, "r+")) == NULL) { WriteError("$Database error: Can't create %s", temp); return; } strncat(msgs.Name,marea,40-strlen(msgs.Name)); strncpy(msgs.Tag,marea,50); strncpy(msgs.QWKname,marea,20); strncat(msgs.Base,marea,64-strlen(msgs.Base)); fseek(pMsgs, 0, SEEK_END); Syslog('+', "Autocreate area %s", marea); memset(&syscon, 0, sizeof(syscon)); syscon.aka.zone = p_from->zone; syscon.aka.node = p_from->node; syscon.aka.net = p_from->net; if (SearchFidonet(p_from->zone)) strcpy(syscon.aka.domain,fidonet.domain); else { WriteError("New area %s from node of unknown zone %d not created.", marea,p_from->zone); fclose(pMsgs); return; } syscon.sendto = TRUE; syscon.receivefrom = TRUE; if (msgs.Aka.zone == 0) { 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; msgs.Aka.point=CFG.aka[i].point; strcpy(msgs.Aka.domain,CFG.aka[i].domain); i=40; } } for (i = 0; i < 40; i++) { if (CFG.akavalid[i] && (strcmp(CFG.aka[i].domain,msgs.Aka.domain)==0)) { msgs.Aka.zone=CFG.aka[i].zone; msgs.Aka.net=CFG.aka[i].net; msgs.Aka.node=CFG.aka[i].node; msgs.Aka.point=CFG.aka[i].point; strcpy(msgs.Aka.domain,CFG.aka[i].domain); i=40; } } for (i = 0; i < 40; i++) { if ((CFG.akavalid[i]) && (CFG.aka[i].zone == p_from->zone)) { msgs.Aka.zone=CFG.aka[i].zone; msgs.Aka.net=CFG.aka[i].net; msgs.Aka.node=CFG.aka[i].node; msgs.Aka.point=CFG.aka[i].point; strcpy(msgs.Aka.domain,CFG.aka[i].domain); i=40; } } for (i = 0; i < 40; i++) { if ((CFG.akavalid[i]) && (CFG.aka[i].zone == p_from->zone) && (CFG.aka[i].net == p_from->net)) { msgs.Aka.zone=CFG.aka[i].zone; msgs.Aka.net=CFG.aka[i].net; msgs.Aka.node=CFG.aka[i].node; msgs.Aka.point=CFG.aka[i].point; strcpy(msgs.Aka.domain,CFG.aka[i].domain); i=40; } } for (i = 0; i < 40; i++) { if ((CFG.akavalid[i]) && (CFG.aka[i].zone == p_from->zone) && (CFG.aka[i].net == p_from->net) && (CFG.aka[i].node == p_from->node)) { msgs.Aka.zone=CFG.aka[i].zone; msgs.Aka.net=CFG.aka[i].net; msgs.Aka.node=CFG.aka[i].node; msgs.Aka.point=CFG.aka[i].point; strcpy(msgs.Aka.domain,CFG.aka[i].domain); i=40; } } } fwrite(&msgs, msgshdr.recsize, 1, pMsgs); fwrite(&syscon, sizeof(syscon), 1, pMsgs); memset(&syscon, 0, sizeof(syscon)); for (i = 1 ; i < CFG.toss_systems; i++ ) fwrite(&syscon, sizeof(syscon), 1, pMsgs); fclose(pMsgs); return; } /* * Toss one packet. * * 0 - * 1 - Cannot open packet * 2 - Bad packet header * 3 - Packet is not for us * 4 - Bad password */ int TossPkt(char *fn) { int rc, count = 0; static int maxrc = 0; static faddr from, to; FILE *pkt; if (!do_quiet) { colour(10, 0); printf("Tossing packet %s\n", fn); } if ((pkt = fopen(fn, "r")) == 0) { WriteError("$Cannot open %s", fn); return 1; } memset(&from, 0, sizeof(faddr)); memset(&to, 0, sizeof(faddr)); if (((rc = getheader(&from, &to, pkt, fn)) != 0)) { WriteError("%s, aborting", (rc == 1)?"wrong header type": (rc == 2)?"bad packet header": (rc == 3)?"packet is not for us": (rc == 4)?"bad password": "bad packet"); return(rc); } while ((rc = getmessage(pkt, &from, &to)) == 1) { count++; } Syslog('+', "Messages : %d", count); maxrc = rc; if (!do_quiet) printf("\r \r"); if (rc) Syslog('+', "End, rc=%d", maxrc); fclose(pkt); return maxrc; } /* * Process one message from message packet. * * 0 - no more messages * 1 - more messages * 2 - bad file * 3 - bad message header * 4 - unable to open temp file * 5 - unexpected end of packet * >10 - import error */ int getmessage(FILE *pkt, faddr *p_from, faddr *p_to) { char buf[2048]; char *orig = NULL; char *p, *l, *r; int tmp, rc, maxrc = 0; static faddr f, t; faddr *o; int result, flags, cost; time_t mdate = 0L; FILE *fp; unsigned char buffer[0x0e]; char *subj = NULL; result = fread(&buffer, 1, sizeof(buffer), pkt); if (result == 0) { Syslog('m', "Zero bytes message, assume end of pkt"); return 0; } switch(tmp = (buffer[0x01] << 8) + buffer[0x00]) { case 0: if (result == 2) return 0; else { Syslog('!', "Junk after logical end of packet, skipped"); return 5; } case 2: break; default: Syslog('!', "bad message type: 0x%04x",tmp); return 2; } if (result != 14) { Syslog('!', "Unexpected end of packet"); return 5; } memset(&f, 0, sizeof(f)); memset(&t, 0, sizeof(t)); f.node = (buffer[0x03] << 8) + buffer[0x02]; t.node = (buffer[0x05] << 8) + buffer[0x04]; f.net = (buffer[0x07] << 8) + buffer[0x06]; t.net = (buffer[0x09] << 8) + buffer[0x08]; flags = (buffer[0x0b] << 8) + buffer[0x0a]; cost = (buffer[0x0d] << 8) + buffer[0x0c]; /* * Read the DateTime, toUserName, fromUserName and subject fields * from the packed message. The stringlength is +1 for the right * check. This is different then in ifmail's original code. */ if (aread(buf, sizeof(buf)-1, pkt)) { if (strlen(buf) > 20) Syslog('!', "date too long (%d) \"%s\"", strlen(buf), printable(buf, 0)); mdate = parsefdate(buf, NULL); if (aread(buf, sizeof(buf)-1, pkt)) { Syslog('!', "date not null-terminated: \"%s\"",buf); return 3; } } if (aread(buf, sizeof(buf)-1, pkt)) { if (strlen(buf) > 36) Syslog('!', "to name too long (%d) \"%s\"", strlen(buf), printable(buf, 0)); t.name = xstrcpy(buf); if (aread(buf, sizeof(buf)-1, pkt)) { if (*(p=t.name+strlen(t.name)-1) == '\n') *p = '\0'; Syslog('!', "to name not null-terminated: \"%s\"",buf); return 3; } } if (aread(buf, sizeof(buf)-1, pkt)) { if (strlen(buf) > 36) Syslog('!', "from name too long (%d) \"%s\"", strlen(buf), printable(buf, 0)); f.name = xstrcpy(buf); if (aread(buf, sizeof(buf)-1, pkt)) { if (*(p=f.name+strlen(f.name)-1) == '\n') *p = '\0'; Syslog('!', "from name not null-terminated: \"%s\"",buf); return 3; } } if (aread(buf, sizeof(buf)-1, pkt)) { if (strlen(buf) > 72) Syslog('!', "subject too long (%d) \"%s\"", strlen(buf), printable(buf, 0)); subj = xstrcpy(buf); if (aread(buf, sizeof(buf)-1, pkt)) { if (*(p=subj+strlen(subj)-1) == '\n') *p = '\0'; subj = xstrcat(subj,(char *)"\\n"); subj = xstrcat(subj,buf); Syslog('!', "subj not null-terminated: \"%s\"",buf); return 3; } } if (feof(pkt) || ferror(pkt)) { Syslog('!', "Could not read message header, aborting"); return 3; } f.zone = p_from->zone; t.zone = p_to->zone; if ((fp = tmpfile()) == NULL) { WriteError("$unable to open temporary file"); return 4; } /* * Read the text from the .pkt file */ while (aread(buf,sizeof(buf)-1,pkt)) { fputs(buf, fp); /* * Extract info from Origin line if found. */ if (!strncmp(buf," * Origin:",10)) { p=buf+10; while (*p == ' ') p++; if ((l=strrchr(p,'(')) && (r=strrchr(p,')')) && (l < r)) { *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 if (*(l=p+strlen(p)-1) == '\n') *l='\0'; for (l=p+strlen(p)-1;*l == ' ';l--) *l='\0'; orig = xstrcpy(p); } } rc = importmsg(p_from, &f,&t,orig,subj,mdate,flags,cost,fp); if (rc) rc+=10; if (rc > maxrc) maxrc = rc; fclose(fp); if(f.name) free(f.name); f.name=NULL; if(t.name) free(t.name); t.name=NULL; if(f.domain) free(f.domain); f.domain=NULL; if(t.domain) free(t.domain); t.domain=NULL; if (subj) free(subj); subj = NULL; if (orig) free(orig); orig = NULL; if (feof(pkt) || ferror(pkt)) { WriteError("Unexpected end of packet"); return 5; } return 1; }