/***************************************************************************** * HPT --- FTN NetMail/EchoMail Tosser ***************************************************************************** * Copyright (C) 1997-1999 * * Matthias Tichy * * Fido: 2:2433/1245 2:2433/1247 2:2432/605.14 * Internet: mtt@tichy.de * * Grimmestr. 12 Buchholzer Weg 4 * 33098 Paderborn 40472 Duesseldorf * Germany Germany * * Copyright (C) 1999-2002 * * Max Levenkov * * Fido: 2:5000/117 * Internet: sackett@mail.ru * Novosibirsk, West Siberia, Russia * * This file is part of HPT. * * HPT 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. * * HPT 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 HPT; see the file COPYING. If not, write to the Free * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************** * $Id: toss.c,v 1.490.2.15 2004/11/28 16:19:06 d_sergienko Exp $ */ #include #include #include #include #include #include /* compiler.h */ #include #if (defined(__EMX__) || defined(__MINGW32__)) && defined(__NT__) /* we can't include windows.h for prevent compiler errors ... */ /*# include */ # define CharToOem CharToOemA #endif #ifdef HAS_UNISTD_H #include #endif #ifdef HAS_IO_H #include #endif #if defined(__OS2__) #include #endif #ifdef HAS_DOS_H #include #endif #if defined(__NT__) /* we can't include windows.h for several reasons ... */ #define GetFileAttributes GetFileAttributesA #endif /* smapi */ #include #include #include #include #include /* fidoconf */ #include #include #include #include #include #include #include #if defined(A_HIDDEN) && !defined(_A_HIDDEN) #define _A_HIDDEN A_HIDDEN #endif #ifdef USE_HPT_ZLIB # include "hpt_zlib/hptzip.h" #endif /* hpt */ #include #include #include #include #include #include #include #include #include #include #include #include "stat.h" #ifdef DO_PERL #include #endif #if defined(__MINGW32__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1100)) #define NOSLASHES #endif extern s_message **msgToSysop; int save_err; static ULONG nopenpkt, maxopenpkt; s_statToss statToss; int forwardPkt(const char *fileName, s_pktHeader *header, e_tossSecurity sec); void processDir(char *directory, e_tossSecurity sec); void makeMsgToSysop(char *areaName, hs_addr fromAddr, ps_addr uplinkAddr); static void setmaxopen(void); static char *get_filename(char *pathname) { char *ptr = NULL; if (pathname == NULL || !(*pathname)) return pathname; ptr = pathname + strlen(pathname) - 1; while (*ptr != '/' && *ptr != '\\' && *ptr != ':' && ptr != pathname) ptr--; if (*ptr == '/' || *ptr == '\\' || *ptr == ':') ptr++; return ptr; } /* return value: 1 if success, 0 if fail */ int putMsgInArea(s_area *echo, s_message *msg, int strip, dword forceattr) { char *ctrlBuff = NULL, *textStart = NULL, *textWithoutArea = NULL; UINT textLength = (UINT) msg->textLength; /* HAREA harea = NULL; */ HMSG hmsg; XMSG xmsg; char /**slash,*/ *p, *q, *tiny; int rc = 0; if (echo->msgbType==MSGTYPE_PASSTHROUGH) { w_log(LL_ERR, "Can't put message to passthrough area %s!", echo->areaName); return rc; } if (!msg->netMail) { msg->destAddr.zone = echo->useAka->zone; msg->destAddr.net = echo->useAka->net; msg->destAddr.node = echo->useAka->node; msg->destAddr.point = echo->useAka->point; } if (maxopenpkt == 0) setmaxopen(); if (echo->harea == NULL) { w_log( LL_SRCLINE, "%s:%d opening %s", __FILE__, __LINE__,echo->fileName); echo->harea = MsgOpenArea((UCHAR *) echo->fileName, MSGAREA_CRIFNEC, /*echo->fperm, echo->uid, echo->gid,*/ (word)(echo->msgbType | (msg->netMail ? 0 : MSGTYPE_ECHO))); if (echo->harea) nopenpkt+=3; } if (echo->harea != NULL) { w_log( LL_SRCLINE, "%s:%d creating msg", __FILE__, __LINE__); hmsg = MsgOpenMsg(echo->harea, MOPEN_CREATE, 0); if (hmsg != NULL) { /* recode from TransportCharset to internal Charset */ if (config->intab != NULL) { if ((msg->recode & REC_HDR)==0) { recodeToInternalCharset((CHAR*)msg->fromUserName); recodeToInternalCharset((CHAR*)msg->toUserName); recodeToInternalCharset((CHAR*)msg->subjectLine); msg->recode |= REC_HDR; } if ((msg->recode & REC_TXT)==0) { recodeToInternalCharset((CHAR*)msg->text); msg->recode |= REC_TXT; } } textWithoutArea = msg->text; if ((strip==1) && (strncmp(msg->text, "AREA:", 5) == 0)) { /* jump over AREA:xxxxx\r */ while (*(textWithoutArea) != '\r') textWithoutArea++; textWithoutArea++; textLength -= (size_t) (textWithoutArea - msg->text); } if (echo->killSB) { tiny = strrstr(textWithoutArea, " * Origin:"); if (tiny == NULL) tiny = textWithoutArea; if (NULL != (p = strstr(tiny, "\rSEEN-BY: "))) { p[1]='\0'; textLength = (size_t) (p - textWithoutArea + 1); } } else if (echo->tinySB) { tiny = strrstr(textWithoutArea, " * Origin:"); if (tiny == NULL) tiny = textWithoutArea; if (NULL != (p = strstr(tiny, "\rSEEN-BY: "))) { p++; if (NULL != (q = strstr(p,"\001PATH: "))) { /* memmove(p,q,strlen(q)+1); */ memmove(p,q,textLength-(size_t)(q-textWithoutArea)+1); textLength -= (size_t) (q - p); } else { p[0]='\0'; textLength = (size_t) (p - textWithoutArea); } } } ctrlBuff = (char *) CopyToControlBuf((UCHAR *) textWithoutArea, (UCHAR **) &textStart, &textLength); /* textStart is a pointer to the first non-kludge line */ xmsg = createXMSG(config,msg, NULL, forceattr,tossDir); w_log( LL_SRCLINE, "%s:%d writing msg", __FILE__, __LINE__); if (MsgWriteMsg(hmsg, 0, &xmsg, (byte *) textStart, (dword) textLength, (dword) textLength, (dword)strlen(ctrlBuff), (byte*)ctrlBuff)!=0) w_log(LL_ERR, "Could not write msg in %s!", echo->fileName); else rc = 1; /* normal exit */ w_log( LL_SRCLINE, "%s:%d closing msg", __FILE__, __LINE__); if (MsgCloseMsg(hmsg)!=0) { w_log(LL_ERR, "Could not close msg in %s!", echo->fileName); rc = 0; } nfree(ctrlBuff); } else w_log(LL_ERR, "Could not create new msg in %s!", echo->fileName); /* endif */ if (nopenpkt>=maxopenpkt-12) { w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,echo->fileName); MsgCloseArea(echo->harea); echo->harea = NULL; nopenpkt-=3; } } else w_log(LL_ERR, "Could not open/create EchoArea %s!", echo->fileName); /* endif */ w_log( LL_SRCLINE, "%s:%d end rc=%d", __FILE__, __LINE__,rc); return rc; } void closeOpenedPkt(void) { unsigned int i; for (i=0; ilinkCount; i++) if (config->links[i].pkt) { if (closeCreatedPkt(config->links[i].pkt)) w_log(LL_ERR,"can't close pkt: %s", config->links[i].pktFile); config->links[i].pkt = NULL; nopenpkt--; } for (i=0; iechoAreaCount; i++) if (config->echoAreas[i].harea) { w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->echoAreas[i].fileName); MsgCloseArea(config->echoAreas[i].harea); config->echoAreas[i].harea = NULL; nopenpkt-=3; } for (i=0; inetMailAreaCount; i++) if (config->netMailAreas[i].harea) { w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->netMailAreas[i].fileName); MsgCloseArea(config->netMailAreas[i].harea); config->netMailAreas[i].harea = NULL; nopenpkt-=3; } for (i=0; ilocalAreaCount; i++) { if (config->localAreas[i].harea) { w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->localAreas[i].fileName); MsgCloseArea(config->localAreas[i].harea); config->localAreas[i].harea = NULL; nopenpkt-=3; } } if (config->badArea.harea) { w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->badArea.fileName); MsgCloseArea(config->badArea.harea); config->badArea.harea = NULL; nopenpkt-=3; } if (config->dupeArea.harea) { w_log( LL_SRCLINE, "%s:%d closing %s", __FILE__, __LINE__,config->dupeArea.fileName); MsgCloseArea(config->dupeArea.harea); config->dupeArea.harea = NULL; nopenpkt-=3; } } void forwardMsgToLink(s_message *msg, s_area *echo, s_link *link, s_seenBy *seenBys, UINT16 seenByCount, s_seenBy *pathArray, UINT16 pathArrayCount) { UINT16 rc=0; ULONG len; s_pktHeader header; s_seenBy *path = NULL; UINT16 pathCount = 0; #ifdef DEBUG_HPT int i; #endif char *start = NULL, *text = NULL, *seenByText = NULL, *pathText = NULL; #ifdef DEBUG_HPT text = createControlText(seenBys, seenByCount, "SEEN-BY: "); w_log(LL_DEBUGS, "forwardMsgToLink:%u: %s", __LINE__, text); nfree(text); text = createControlText(pathArray, pathArrayCount, "PATH: "); w_log(LL_DEBUGS, "forwardMsgToLink:%u: %s", __LINE__, text); nfree(text); #endif /* add our aka to path */ if (pathArrayCount > 0) { path = memdup(pathArray, sizeof(s_seenBy) * pathArrayCount); pathCount = pathArrayCount; if ((path[pathCount-1].net != link->ourAka->net) || (path[pathCount-1].node != link->ourAka->node)) { path = (s_seenBy*) safe_realloc(path, sizeof(s_seenBy) * (pathCount+1)); path[pathCount].net = (UINT16) link->ourAka->net; path[pathCount].node = (UINT16) link->ourAka->node; pathCount++; } } else { pathCount = 0; path = (s_seenBy*) safe_calloc(sizeof(s_seenBy), 1); path[pathCount].net = (UINT16) link->ourAka->net; path[pathCount].node = (UINT16) link->ourAka->node; pathCount = 1; } #ifdef DEBUG_HPT for (i=0; i< pathCount;i++) printf("%u/%u ", path[i].net, path[i].node); #endif text = strrstr(msg->text, " * Origin:"); /* jump over Origin */ if (text) { /* origin was found */ start = strrchr(text, ')'); if (start) start++; /* normal origin */ else { start = text; /* broken origin */ while(*start && *start!='\r') start++; } *start='\0'; } else { /* no Origin was found */ text = msg->text; start = strstr(text, "\rSEEN-BY: "); if (start == NULL) start = strstr(text, "SEEN-BY: "); if (start) *start='\0'; /* find the start of PATH in Msg */ start = strstr(text, "\001PATH: "); if (start) *start='\0'; else start = text+strlen(text); } msg->textLength = (size_t) (start - msg->text); /* create new seenByText */ #ifdef DEBUG_HPT text = createControlText(seenBys, seenByCount, "SEEN-BY: "); w_log(LL_DEBUGS, "forwardMsgToLink:%u: %s", __LINE__, text); text = createControlText(path, pathCount, "PATH: "); w_log(LL_DEBUGS, "forwardMsgToLink:%u: %s", __LINE__, text); nfree(text); #endif seenByText = createControlText(seenBys, seenByCount, "SEEN-BY: "); pathText = createControlText(path, pathCount, "\001PATH: "); xstrscat(&msg->text, "\r", seenByText, pathText, NULL); msg->textLength += 1 + strlen(seenByText) + strlen(pathText); nfree(seenByText); nfree(pathText); /* add msg to the pkt's of the downlinks */ if (maxopenpkt == 0) setmaxopen(); /* check packet size */ if (link->pktFile != NULL && link->pktSize != 0) { len = link->pkt ? ftell(link->pkt) : fsize(link->pktFile); if (len >= (link->pktSize * 1024L)) { /* Stop writing to pkt */ if (link->pkt) { fclose(link->pkt); link->pkt = NULL; nopenpkt--; } nfree(link->pktFile); nfree(link->packFile); } } /* create pktfile if necessary */ if (link->pktFile == NULL) { /* pktFile does not exist */ if ( createTempPktFileName(link) ) exit_hpt("Could not create new pkt!",1); } makePktHeader(NULL, &header); header.origAddr = *(link->ourAka); header.destAddr = link->hisAka; if (link->pktPwd != NULL) strcpy(header.pktPassword, link->pktPwd); if (link->pkt == NULL) { link->pkt = openPktForAppending(link->pktFile, &header); nopenpkt++; } /* an echomail msg must be adressed to the link */ msg->destAddr = header.destAddr; /* .. and must come from us */ msg->origAddr = header.origAddr; rc += writeMsgToPkt(link->pkt, *msg); if (rc) w_log(LL_ERR,"can't write msg to pkt: %s", link->pktFile); if (nopenpkt >= maxopenpkt-12 || /* std streams, in pkt, msgbase, log */ (link->pktSize && ftell(link->pkt)>= (long)link->pktSize*1024L)) { rc += closeCreatedPkt(link->pkt); if (rc) w_log(LL_ERR,"can't close pkt: %s", link->pktFile); link->pkt = NULL; nopenpkt--; } if (rc==0) statToss.exported++; else rc=0; #ifdef ADV_STAT if (config->advStatisticsFile != NULL) put_stat(echo, &(header.destAddr), stOUT, msg->textLength); #endif return; } void forwardMsgToLinks_rsb(s_area *echo, s_message *msg, hs_addr pktOrigAddr, UINT16 rsb) { s_seenBy *seenBys = NULL, *path = NULL; UINT16 seenByCount = 0 , pathCount = 0; int i; char *text; /* links who does not have their aka in seenBys and thus have not got the echomail */ s_arealink **newLinks = NULL; /* init array of seen-bys */ zero_seenBysZone(); #ifdef DEBUG_HPT print_seenBysZone(); #endif /* fetch seen-bys from msg */ createSeenByArrayFromMsg(msg, &seenBys, &seenByCount); text = createControlText(seenBys, seenByCount, ""); #ifdef DEBUG_HPT w_log(LL_DEBUGS, "forwardMsgToLinks_rsb:%u: SEEN-BY: %s", __LINE__, text); #endif /* fetch path from msg */ createPathArrayFromMsg(msg, &path, &pathCount); text = createControlText(path, pathCount, ""); #ifdef DEBUG_HPT w_log(LL_DEBUGS, "forwardMsgToLinks_rsb:%u: PATH: %s", __LINE__, text); #endif if (rsb == 0) { /* attach seen-bys of message to seenBysZone with zone == pktOrigAddr.zone */ attachTo_seenBysZone(pktOrigAddr.zone, &seenBys, seenByCount); text = createControlText(seenBys, seenByCount, ""); #ifdef DEBUG_HPT w_log(LL_DEBUGS, "forwardMsgToLinks_rsb:%u: SEEN-BY: %s", __LINE__, text); #endif } else { /* attach path to seenBysZone with zone == pktOrigAddr.zone */ attachTo_seenBysZone(pktOrigAddr.zone, &path, pathCount); text = createControlText(path, pathCount, ""); #ifdef DEBUG_HPT w_log(LL_DEBUGS, "forwardMsgToLinks_rsb:%u: PATH: %s", __LINE__, text); #endif /* make a copy of path 'cause 1st is left for seen-bys */ path = memdup(path, sizeof(s_seenBy) * pathCount); } /* add seen-bys from addToSeen & -sbadd to all zones */ processAutoAdd_seenByZone(echo); #ifdef DEBUG_HPT w_log(LL_DEBUGS, "after processAutoAdd_seenByZone()"); print_seenBysZone(); #endif /* build an array of links who will receive this message */ createNewLinksArray(echo, &newLinks, pktOrigAddr, rsb); /* append AKAs of links to seen-by array with sorting by zone */ addLinksTo_seenByZone(newLinks, echo->downlinkCount); #ifdef DEBUG_HPT w_log(LL_DEBUGS, "after addLinksTo_seenByZone()"); print_seenBysZone(); #endif /* add all our AKAs */ addAkasTo_seenByZone(); #ifdef DEBUG_HPT w_log(LL_DEBUGS, "after addAkasTo_seenByZone()"); print_seenBysZone(); #endif cleanDupes_seenByZone(); #ifdef DEBUG_HPT w_log(LL_DEBUGS, "after cleanDupes_seenByZone()"); print_seenBysZone(); #endif /* forward message to each links from an array */ for (i=0;idownlinkCount;i++) { if (newLinks==NULL || newLinks[i] == NULL) break; /* end of list */ /* forward message to link */ forwardMsgToLink(msg, echo, newLinks[i]->link, seenBysZone[newLinks[i]->link->hisAka.zone].seenByArray, seenBysZone[newLinks[i]->link->hisAka.zone].seenByCount, path, pathCount); } /* free all used memory */ free_seenBysZone(); #ifdef DEBUG_HPT w_log(LL_DEBUGS, "after free_seenByZone()"); print_seenBysZone(); #endif nfree(path); nfree(newLinks); } void forwardMsgToLinks(s_area *echo, s_message *msg, hs_addr pktOrigAddr) { char *msgtext; UINT16 textlen; msgtext = safe_strdup(msg->text); textlen = msg->textLength; /* forward message to all links with normal seen-bys */ forwardMsgToLinks_rsb(echo, msg, pktOrigAddr, 0); /* restore original message text with original path & seen-bys */ nfree(msg->text); msg->text = safe_strdup(msgtext); msg->textLength = textlen; /* and now forward message to links with reduced seen-bys */ forwardMsgToLinks_rsb(echo, msg, pktOrigAddr, 1); /* restore original message text with original path & seen-bys */ nfree(msg->text); msg->text = safe_strdup(msgtext); msg->textLength = textlen; } /* return value: 1 if success, 0 if fail */ int putMsgInBadArea(s_message *msg, hs_addr pktOrigAddr, int writeAccess) { char *tmp = NULL, *line = NULL, *textBuff=NULL, *areaName=NULL, *reason=NULL; char buff[128] = ""; w_log(LL_FUNC, "putMsgInBadArea() begin"); statToss.bad++; /* get real name area */ line = strchr(msg->text, '\r'); if (strncmp(msg->text,"AREA:",5)==0) { *line = 0; xstrcat(&areaName, msg->text+5); *line = '\r'; } switch (writeAccess) { case 0: reason = "System not allowed to create new area"; w_log(LL_ECHOMAIL, "Badmail reason: System not allowed to create new area (%s)", areaName); break; case 1: reason = "Sender not allowed to post in this area (access group)"; w_log(LL_ECHOMAIL, "Badmail reason: Sender not allowed to post in area %s (access group)", areaName); break; case 2: reason = "Sender not allowed to post in this area (access level)"; w_log(LL_ECHOMAIL, "Badmail reason: Sender not allowed to post in area %s (access level)", areaName); break; case 3: reason = "Sender not allowed to post in this area (access import)"; w_log(LL_ECHOMAIL, "Badmail reason: Sender not allowed to post in area %s (access import)", areaName); break; case 4: reason = "Sender not active for this area"; w_log(LL_ECHOMAIL, "Badmail reason: Sender not active for area %s", areaName); break; case 5: reason = "Rejected by filter"; w_log(LL_ECHOMAIL, "Badmail reason: Rejected by filter"); break; case 6: /* MSGAPI error */ reason = strncat( strcpy(buff,"MSGAPIERR: "), strmerr(msgapierr), sizeof(buff)-sizeof("MSGAPIERR: ") ); w_log(LL_ECHOMAIL, "Badmail reason: %s", reason); break; case 7: reason = "Can't create echoarea with forbidden symbols in areatag"; w_log(LL_ECHOMAIL, "Badmail reason: Can't create echoarea with forbidden symbols in areatag: '%s'", areaName); break; case 8: reason = "Sender not found in config file"; w_log(LL_ECHOMAIL, "Badmail reason: Sender not found in config file"); break; case 9: reason = "Can't open config file"; w_log(LL_ECHOMAIL, "Badmail reason: Can't open config file"); break; case 10: reason = "No downlinks for passthrough area"; w_log(LL_ECHOMAIL, "Badmail reason: No downlinks for passthrough area '%s'", areaName); break; case 11: reason = "lenght of CONFERENCE name is more than 60 symbols"; w_log(LL_ECHOMAIL, "Badmail reason: lenght of CONFERENCE name (areatag) is more than 60 symbols: '%s'", areaName); break; case 12: reason = "Area killed (unsubscribed)"; w_log(LL_ECHOMAIL, "Badmail reason: area killed (unsubscribed): '%s'", areaName); break; case 13: reason = "New area refused by NewAreaRefuseFile"; w_log(LL_ECHOMAIL, "Badmail reason: New area '%s' refused by NewAreaRefuseFile", areaName); break; default : reason = "Another error"; w_log(LL_ECHOMAIL, "Badmail reason: Another error"); break; } #ifdef DO_PERL if (perltossbad(msg, areaName, pktOrigAddr, reason)) { nfree(areaName); nfree(msg->text); w_log(LL_FUNC, "putMsgInBadArea():perltossbad OK (rc=1)"); return 1; } #endif tmp = msg->text; while ((line = strchr(tmp, '\r')) != NULL) { if (*(line+1) == '\x01') tmp = line+1; else { tmp = line+1; *line = 0; break; } } xstrscat(&textBuff, msg->text, "\rFROM: ", aka2str(pktOrigAddr), "\rREASON: ", reason, "\r", NULL); if (areaName) xscatprintf(&textBuff, "AREANAME: %s\r\r", areaName); xstrcat(&textBuff, tmp); nfree(areaName); nfree(msg->text); msg->text = textBuff; msg->textLength = strlen(msg->text); if (putMsgInArea(&(config->badArea), msg, 0, 0)) { config->badArea.imported++; w_log(LL_FUNC, "putMsgInBadArea() OK"); return 1; } w_log(LL_FUNC, "putMsgInBadArea() failed"); return 0; } void makeMsgToSysop(char *areaName, hs_addr fromAddr, ps_addr uplinkAddr) { s_area *echo = NULL; unsigned int i, netmail=0; char *buff=NULL; char *strbeg=NULL; if (config->ReportTo) { if (stricmp(config->ReportTo,"netmail")==0) netmail=1; else if (getNetMailArea(config, config->ReportTo) != NULL) netmail=1; } else netmail=1; echo = getArea(config, areaName); if (echo == &(config->badArea)) return; for (i = 0; i < config->addrCount; i++) { if (echo->useAka == &(config->addr[i])) { if (msgToSysop[i] == NULL) { msgToSysop[i] = makeMessage(echo->useAka, echo->useAka, config->areafixFromName ? config->areafixFromName : versionStr, netmail ? (config->sysop ? config->sysop : "Sysop") : "All", "Created new areas", netmail, config->areafixReportsAttr); msgToSysop[i]->text = createKludges(config, netmail ? NULL : config->ReportTo, echo->useAka, echo->useAka, versionStr); if (config->areafixReportsFlags) xstrscat(&(msgToSysop[i]->text), "\001FLAGS ", config->areafixReportsFlags, "\r", NULL); xstrscat(&(msgToSysop[i]->text), "Action Name", print_ch(49, ' '), "By\r", NULL); /* Shitty static variables .... */ xstrscat(&(msgToSysop[i]->text), print_ch(79, '-'), "\r", NULL); msgToSysop[i]->recode |= (REC_HDR|REC_TXT); w_log(LL_NETMAIL,"Created msg to sysop"); } /* New report generation */ xstrcat(&buff, aka2str(fromAddr)); if (uplinkAddr != NULL) { /* autocreation with forward request */ xstrcat(&buff, " from "); xstrcat(&buff, aka2str(*uplinkAddr)); } xstrscat(&strbeg, "Created ", echo->areaName, NULL); if (echo->description) { if (strlen(strbeg) + strlen(echo->description) >=77) { xstrscat(&(msgToSysop[i]->text), strbeg, "\r", NULL); nfree(strbeg); xstrcat(&strbeg, print_ch(9, ' ')); } else { xstrcat(&strbeg, " "); } xstrscat(&strbeg, "\"", echo->description, "\"", NULL); } xstrcat(&(msgToSysop[i]->text), strbeg); if (strlen(strbeg) + strlen(buff) >= 79) { xstrscat(&(msgToSysop[i]->text), "\r", print_ch(79-strlen(buff), ' '), buff, "\r", NULL); } else if (strlen(strbeg) <62 && strlen(buff) < 79-62) { /* most beautiful */ xstrscat(&(msgToSysop[i]->text), print_ch(62-strlen(strbeg), ' '), buff, "\r", NULL); } else { xstrscat(&(msgToSysop[i]->text), print_ch(79-strlen(strbeg)-strlen(buff), ' '), buff, "\r", NULL); } nfree(buff); nfree(strbeg); break; } } } void writeMsgToSysop() { char *ptr = NULL, *seenByPath = NULL; s_area *echo = NULL; unsigned int i, ccrc = 0; s_seenBy *seenBys = NULL; for (i = 0; i < config->addrCount; i++) { if (msgToSysop[i]) { xscatprintf(&(msgToSysop[i]->text), " \r--- %s\r * Origin: %s (%s)\r", (config->tearline) ? config->tearline : "", (config->origin) ? config->origin : config->name, aka2str(msgToSysop[i]->origAddr)); msgToSysop[i]->textLength = strlen(msgToSysop[i]->text); if (msgToSysop[i]->netMail == 1) /* FIXME: should be putMsgInArea */ processNMMsg(msgToSysop[i], NULL, config->ReportTo ? getNetMailArea(config, config->ReportTo) : NULL, 1, 0); else { /* get echoarea for this msg */ ptr = strchr(msgToSysop[i]->text, '\r'); *ptr = '\0'; echo = getArea(config, msgToSysop[i]->text + 5); *ptr = '\r'; if (echo != &(config->badArea)) { if (config->carbonCount != 0) ccrc = carbonCopy(msgToSysop[i], NULL, echo); if (echo->msgbType != MSGTYPE_PASSTHROUGH && ccrc <= 1) { putMsgInArea(echo, msgToSysop[i],1, (MSGSCANNED|MSGSENT|MSGLOCAL)); echo->imported++; /* area has got new messages */ } seenBys = (s_seenBy*) safe_malloc(sizeof(s_seenBy)*(echo->downlinkCount+1)); seenBys[0].net = (UINT16) echo->useAka->net; seenBys[0].node = (UINT16) echo->useAka->node; sortSeenBys(seenBys, 1); seenByPath = createControlText(seenBys, 1, "SEEN-BY: "); nfree(seenBys); /* path line */ /* only include node-akas in path */ if (echo->useAka->point == 0) xscatprintf(&seenByPath, "\001PATH: %u/%u\r", echo->useAka->net, echo->useAka->node); xstrcat(&(msgToSysop[i]->text), seenByPath); nfree(seenByPath); if (echo->downlinkCount > 0) { /* recoding from internal to transport charSet */ if (config->outtab) { if (msgToSysop[i]->recode & REC_HDR) { recodeToTransportCharset((CHAR*)msgToSysop[i]->fromUserName); recodeToTransportCharset((CHAR*)msgToSysop[i]->toUserName); recodeToTransportCharset((CHAR*)msgToSysop[i]->subjectLine); msgToSysop[i]->recode &= ~REC_HDR; } if (msgToSysop[i]->recode & REC_TXT) { recodeToTransportCharset((CHAR*)msgToSysop[i]->text); msgToSysop[i]->recode &= ~REC_TXT; } } forwardMsgToLinks(echo, msgToSysop[i], msgToSysop[i]->origAddr); closeOpenedPkt(); tossTempOutbound(config->tempOutbound); } } else { putMsgInBadArea(msgToSysop[i], msgToSysop[i]->origAddr, 0); } } } } } s_arealink *getAreaLink(s_area *area, hs_addr aka) { UINT i; for (i = 0; i downlinkCount; i++) { if (addrComp(aka, area->downlinks[i]->link->hisAka)==0) return area->downlinks[i]; } return NULL; } /* import: type == 0, export: type != 0 */ /* return value: 0 if access ok, 3 if import/export off, 4 if not linked */ int checkAreaLink(s_area *area, hs_addr aka, int type) { s_arealink *arealink = NULL; int writeAccess = 0; arealink = getAreaLink(area, aka); if (arealink) { if (type==0) { if (arealink->import) writeAccess = 0; else writeAccess = 3; } else { if (arealink->export) writeAccess = 0; else writeAccess = 3; } } else { if (addrComp(aka, *area->useAka)==0) writeAccess = 0; else writeAccess = 4; } return writeAccess; } int processEMMsg(s_message *msg, hs_addr pktOrigAddr, int dontdocc, dword forceattr) { char *area=NULL, *p = NULL, *q = NULL; s_message* messCC = NULL; s_area *echo=&(config->badArea); s_link *link = NULL; int writeAccess = 0, rc = 0, ccrc = 0; w_log(LL_FUNC, "%s::processEMMsg() begin", __FILE__); p = strchr(msg->text,'\r'); if (p) { *p='\0'; q = msg->text+5; while (*q == ' ') q++; xstrcat(&area, q); echo = getArea(config, area); *p='\r'; } /* no area found -- trying to autocreate echoarea */ if (echo == &(config->badArea)) { /* check if we should not refuse this area */ /* checking for autocreate option */ link = getLinkFromAddr(config, pktOrigAddr); if ((link != NULL) && (link->autoAreaCreate != 0)) { if (0 == (writeAccess = autoCreate(area, pktOrigAddr, NULL))) echo = getArea(config, area); else rc = putMsgInBadArea(msg, pktOrigAddr, writeAccess); } /* can't create echoarea - put msg in BadArea */ else rc = putMsgInBadArea(msg, pktOrigAddr, writeAccess); } nfree(area); if (echo != &(config->badArea)) { /* area is autocreated! */ /* cheking access of this link */ writeAccess = checkAreaLink(echo, pktOrigAddr, 0); if (writeAccess) { rc = putMsgInBadArea(msg, pktOrigAddr, writeAccess); #ifdef ADV_STAT if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stBAD, 0); #endif } else { /* access ok - process msg */ if (dupeDetection(echo, *msg)==1) { /* no dupe */ messCC = MessForCC(msg); /* make copy of original message */ statToss.echoMail++; /* if only one downlink, we've got the mail from him */ if ((echo->downlinkCount > 1) || ((echo->downlinkCount > 0) && /* mail from us */ (addrComp(pktOrigAddr,*echo->useAka)==0))) forwardMsgToLinks(echo, msg, pktOrigAddr); #ifdef DEBUG_HPT w_log( LL_SRCLINE, "%s::processEMMsg():%d", __FILE__, __LINE__); #endif /* todo: remove TID from local-generated msgs by hpt post -x * (if (addrComp(pktOrigAddr,*echo->useAka)==0)) */ if (messCC && !dontdocc) ccrc=carbonCopy(messCC, NULL, echo); #ifdef DEBUG_HPT w_log( LL_SRCLINE, "%s::processEMMsg():%d", __FILE__, __LINE__); #endif if (ccrc <= 1) { echo->imported++; /* area has got new messages */ #ifdef ADV_STAT if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stNORM, msg->textLength); #endif if (echo->msgbType != MSGTYPE_PASSTHROUGH) { if(messCC) rc = putMsgInArea(echo, messCC, 1, forceattr); else rc = putMsgInArea(echo, msg, 1, forceattr); statToss.saved += rc; } else { /* passthrough */ /* if (echo->downlinkCount==1 && dontdocc==0) rc = putMsgInBadArea(msg, pktOrigAddr, 10); else { statToss.passthrough++; rc = 1; } */ statToss.passthrough++; rc = 1; } } else rc = 1; /* normal exit for carbon move & delete */ freeMsgBuffers(messCC); nfree(messCC); } else { /* msg is dupe */ if (echo->dupeCheck == dcMove) { /* rc = putMsgInDupeArea(pktOrigAddr, msg, forceattr); */ rc = putMsgInArea(&(config->dupeArea), msg, 0, forceattr); } else rc = 1; statToss.dupes++; #ifdef ADV_STAT if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stDUPE, 0); #endif if (rc) config->dupeArea.imported++; } } } w_log(LL_FUNC, "%s::processEMMsg() rc=%d", __FILE__, rc); return rc; } int processNMMsg(s_message *msg, s_pktHeader *pktHeader, s_area *area, int dontdocc, dword forceattr) { HAREA netmail; HMSG msgHandle; UINT len = 0; char *bodyStart = NULL; /* msg-body without kludgelines start */ char *ctrlBuf = NULL; /* Kludgelines */ XMSG msgHeader; /* char *slash = NULL; */ unsigned int rc = 0, ccrc = 0, i; if (area == NULL) { area = &(config->netMailAreas[0]); for(i=0; inetMailAreaCount; i++) { if(addrComp(msg->destAddr,*(config->netMailAreas[i].useAka))==0) { area = &(config->netMailAreas[i]); break; } } } if (dupeDetection(area, *msg)==0) { /* msg is dupe */ if (area->dupeCheck == dcMove) { rc = putMsgInArea(&(config->dupeArea), msg, 0, forceattr); } else rc = 1; statToss.dupes++; if (rc) config->dupeArea.imported++; return rc; } if ((config->carbonCount!=0)&&(!dontdocc)) ccrc = carbonCopy(msg, NULL, area); if (ccrc > 1) return 1; /* carbon del or move */ netmail = MsgOpenArea((unsigned char *) area -> fileName, MSGAREA_CRIFNEC, /* config->netMailArea.fperm, config->netMailArea.uid, config->netMailArea.gid, */(word) area -> msgbType); if (netmail != NULL) { msgHandle = MsgOpenMsg(netmail, MOPEN_CREATE, 0); if (msgHandle != NULL) { area -> imported++; /* area has got new messages */ /* recode from TransportCharset to internal Charset */ if (config->intab != NULL) { if ((msg->recode & REC_HDR)==0) { recodeToInternalCharset((CHAR*)msg->fromUserName); recodeToInternalCharset((CHAR*)msg->toUserName); recodeToInternalCharset((CHAR*)msg->subjectLine); msg->recode |= REC_HDR; } if ((msg->recode & REC_TXT)==0) { recodeToInternalCharset((CHAR*)msg->text); msg->recode |= REC_TXT; } } msgHeader = createXMSG(config,msg, pktHeader, forceattr,tossDir); /* Create CtrlBuf for SMAPI */ len = msg->textLength; ctrlBuf = (char *) CopyToControlBuf((UCHAR *) msg->text, (UCHAR **) &bodyStart, &len); /* write message */ if (MsgWriteMsg(msgHandle, 0, &msgHeader, (UCHAR *) bodyStart, len, len, strlen(ctrlBuf)+1, (UCHAR *) ctrlBuf)!=0) w_log(LL_ERR,"Could not write msg to NetmailArea %s",area->areaName); else rc = 1; /* normal exit */ nfree(ctrlBuf); if (MsgCloseMsg(msgHandle)!=0) { /* can't close */ w_log(LL_ERR,"Could not close msg in NetmailArea %s",area->areaName); rc = 0; } else { /* normal close */ w_log(LL_NETMAIL, "Wrote Netmail: %u:%u/%u.%u -> %u:%u/%u.%u", msg->origAddr.zone, msg->origAddr.net, msg->origAddr.node, msg->origAddr.point, msg->destAddr.zone, msg->destAddr.net, msg->destAddr.node, msg->destAddr.point); statToss.netMail++; } } else { w_log(LL_ERR, "Could not create new msg in NetmailArea %s", area -> areaName); } /* endif */ MsgCloseArea(netmail); } else { fprintf(stderr, "msgapierr - %u\n", msgapierr); w_log(LL_ERR, "Could not open NetmailArea %s", area -> areaName); } /* endif */ return rc; } int processMsg(s_message *msg, s_pktHeader *pktHeader, int secure) { int rc; w_log(LL_FUNC,"toss.c::processMsg()"); statToss.msgs++; #ifdef DO_PERL w_log(LL_SRCLINE, "toss.c:%u:processMsg() #ifdef DO_PERL", __LINE__); if ((rc = perlfilter(msg, pktHeader->origAddr, secure)) == 1) return putMsgInBadArea(msg, pktHeader->origAddr, 5); else if (rc == 2) return 1; #else /* prevent compiler warning */ secure = secure; #endif if (msg->netMail == 1) { w_log(LL_NETMAIL, "Netmail from %s to %u:%u/%u.%u", aka2str(msg->origAddr), msg->destAddr.zone, msg->destAddr.net, msg->destAddr.node, msg->destAddr.point); if (config->areafixFromPkt && isOurAka(config, msg->destAddr) && strlen(msg->toUserName)>0 && fc_stristr(config->areafixNames,msg->toUserName)) { rc = processAreaFix(msg, pktHeader, 0); } else rc = processNMMsg(msg, pktHeader, NULL, 0, 0); } else { rc = processEMMsg(msg, pktHeader->origAddr, 0, 0); } /* endif */ w_log(LL_FUNC,"toss.c::processMsg() rc=%d", rc); return rc; } int processPkt(char *fileName, e_tossSecurity sec) { FILE *pkt = NULL; s_pktHeader *header = NULL; s_message *msg = NULL; s_link *link = NULL; int rc = 0, msgrc = 0; long pktlen; time_t realtime; /* +AS+ */ char *extcmd = NULL; int cmdexit; /* -AS- */ char processIt = 0; /* processIt = 1, process all mails */ /* processIt = 2, process only Netmail */ /* processIt = 0, do not process pkt */ w_log(LL_FUNC,"toss.c::processPkt()"); if ((pktlen = fsize(fileName)) > 60) { statToss.inBytes += pktlen; /* +AS+ */ if (config->processPkt) { extcmd = safe_malloc(strlen(config->processPkt)+strlen(fileName)+2); sprintf(extcmd,"%s %s",config->processPkt,fileName); w_log(LL_EXEC, "ProcessPkt: execute string \"%s\"",extcmd); if ((cmdexit = cmdcall(extcmd)) != 0) w_log(LL_ERR, "exec failed, code %d", cmdexit); nfree(extcmd); } /* -AS- */ #ifdef DO_PERL if (perlpkt(fileName, (sec==secLocalInbound || sec==secProtInbound) ? 1 : 0)) return 6; #endif pkt = fopen(fileName, "rb"); if (pkt == NULL) return 2; w_log(LL_FILE,"toss.c:processPkt(): opened '%s' (\"rb\" mode)",fileName); header = openPkt(pkt); if (header != NULL) { /* if ((to_us(header->destAddr)==0) || (sec == secLocalInbound)) { */ if ( isOurAka(config,header->destAddr) || (sec == secLocalInbound)) { w_log(LL_PKT, "pkt: %s [%s]", fileName, aka2str(header->origAddr)); statToss.pkts++; link = getLinkFromAddr(config, header->origAddr); if ((link!=NULL) && (link->pktPwd==NULL) && (header->pktPassword[0]!='\000')) w_log(LL_ERR, "Unexpected Password %s.", header->pktPassword); switch (sec) { case secLocalInbound: processIt = 1; break; case secProtInbound: if ((link != NULL) && (link->pktPwd != NULL) && link->pktPwd[0]) { if (stricmp(link->pktPwd, header->pktPassword)==0) { processIt = 1; } else { if ( (header->pktPassword == NULL || header->pktPassword[0] == '\0') && (link->allowEmptyPktPwd & (eSecure | eOn)) ) { w_log(LL_WARN, "pkt: %s Warning: missing packet password from %i:%i/%i.%i", fileName, header->origAddr.zone, header->origAddr.net, header->origAddr.node, header->origAddr.point); processIt = 1; } else { w_log(LL_WARN, "pkt: %s Password Error for %i:%i/%i.%i", fileName, header->origAddr.zone, header->origAddr.net, header->origAddr.node, header->origAddr.point); if (header->pktPassword == NULL || header->pktPassword[0] == '\0') processIt = 2; else rc = 1; } } } else if ((link != NULL) && ((link->pktPwd == NULL) || (strcmp(link->pktPwd, "")==0))) { processIt=1; } else /* if (link == NULL) */ { w_log(LL_ERR, "pkt: %s No Link for %i:%i/%i.%i, processing only Netmail", fileName, header->origAddr.zone, header->origAddr.net, header->origAddr.node, header->origAddr.point); processIt = 2; } break; case secInbound: if ((link != NULL) && (link->pktPwd != NULL) && link->pktPwd[0]) { if (header->pktPassword && stricmp(link->pktPwd, header->pktPassword)==0) { processIt = 1; } else { if ( (header->pktPassword == NULL || header->pktPassword[0] == '\0') && (link->allowEmptyPktPwd & (eOn)) ) { w_log(LL_ERR, "pkt: %s Warning: missing packet password from %i:%i/%i.%i", fileName, header->origAddr.zone, header->origAddr.net, header->origAddr.node, header->origAddr.point); processIt = 2; /* Unsecure inbound, do not process echomail */ } else { w_log(LL_ERR, "pkt: %s Password Error for %i:%i/%i.%i", fileName, header->origAddr.zone, header->origAddr.net, header->origAddr.node, header->origAddr.point); rc = 1; } } } else if ((link != NULL) && ((link->pktPwd == NULL) || (strcmp(link->pktPwd, "")==0))) { processIt=1; } else /* if (link == NULL) */ { w_log(LL_ERR, "pkt: %s No Link for %i:%i/%i.%i, processing only Netmail", fileName, header->origAddr.zone, header->origAddr.net, header->origAddr.node, header->origAddr.point); processIt = 2; } break; } if (processIt != 0) { realtime = time(NULL); while ((msgrc = readMsgFromPkt(pkt, header, &msg)) == 1) { if (msg != NULL) { if ((processIt == 1) || ((processIt==2) && (msg->netMail==1))) { if (processMsg(msg, header, (sec==secLocalInbound || sec==secProtInbound || processIt == 1) ? 1 : 0) != 1 ) if (putMsgInBadArea(msg, header->origAddr, 6)==0) rc = 5; /* can't write to badArea - rename to .err */ } else rc = 1; freeMsgBuffers(msg); nfree(msg); } } if (msgrc==2) rc = 3; /* rename to .bad (wrong msg format) */ /* real time of process pkt & msg without external programs */ statToss.realTime += time(NULL) - realtime; } } else { realtime = time(NULL); while ((msgrc = readMsgFromPkt(pkt, header, &msg)) == 1) { if (msg != NULL) { if (msg->netMail==1) { if (processMsg(msg, header, (sec==secLocalInbound || sec==secProtInbound) ? 1 : 0) !=1 ) rc=5; } else break; freeMsgBuffers(msg); nfree(msg); } } if (msg) { /* echomail pkt not for us */ freeMsgBuffers(msg); nfree(msg); /* PKT is not for us - try to forward it to our links */ w_log(LL_ERR, "pkt: %s addressed to %d:%d/%d.%d but not for us", fileName, header->destAddr.zone, header->destAddr.net, header->destAddr.node, header->destAddr.point); fclose(pkt); pkt = NULL; rc = forwardPkt(fileName, header, sec); } } nfree(header); } else { /* header == NULL */ w_log(LL_ERR, "pkt: %s wrong pkt-file", fileName); rc = 3; } if (pkt) fclose(pkt); } else statToss.empty++; #ifdef DO_PERL perlpktdone(fileName, rc); #endif closeOpenedPkt(); w_log(LL_FUNC,"toss.c::processPkt() OK"); return rc; } int processArc(char *fileName, e_tossSecurity sec) { unsigned int i; int found, j; signed int cmdexit; FILE *bundle = NULL; char cmd[256]; if (sec == secInbound) { w_log(LL_ERR, "bundle %s: tossing in unsecure inbound, security violation", fileName); return 1; }; /* find what unpacker to use */ for (i = 0, found = 0; (i < config->unpackCount) && !found; i++) { bundle = fopen(fileName, "rb"); if (bundle == NULL) return 2; w_log(LL_FILE,"toss.c:processArc(): opened '%s' (\"rb\" mode)",fileName); /* is offset is negative we look at the end */ fseek(bundle, config->unpack[i].offset, config->unpack[i].offset >= 0 ? SEEK_SET : SEEK_END); if (ferror(bundle)) { fclose(bundle); continue; }; for (found = 1, j = 0; j < config->unpack[i].codeSize; j++) { if ((getc(bundle) & config->unpack[i].mask[j]) != config->unpack[i].matchCode[j]) found = 0; } fclose(bundle); } /* unpack bundle */ if (found) { fillCmdStatement(cmd,config->unpack[i-1].call,fileName,"",config->tempInbound); if( fc_stristr(config->unpack[i-1].call, "zipInternal") ) { w_log(LL_BUNDLE, "bundle %s: unpacking with zlib", fileName); #ifdef USE_HPT_ZLIB cmdexit = UnPackWithZlib(fileName, config->tempInbound); #else cmdexit = 1; w_log(LL_ERR, "zlib not compiled into hpt", fileName); #endif } else { w_log(LL_EXEC, "bundle %s: unpacking with \"%s\"", fileName, cmd); if ((cmdexit = cmdcall(cmd)) != 0) { w_log(LL_ERR, "exec failed, code %d", cmdexit); return 3; } } if (config->afterUnpack) { w_log(LL_EXEC, "afterUnpack: execute string \"%s\"", config->afterUnpack); if ((cmdexit = cmdcall(config->afterUnpack)) != 0) { w_log(LL_ERR, "exec failed, code %d", cmdexit); }; } #ifdef DO_PERL perlafterunp(); #endif } else { w_log(LL_ERR, "bundle %s: cannot find unpacker", fileName); return 3; }; statToss.arch++; remove(fileName); processDir(config->tempInbound, sec); return 7; } typedef struct fileInDir { char *fileName; time_t fileTime; } s_fileInDir; int filesComparer(const void *elem1, const void *elem2) { /* File times comparer for qsort */ if (((s_fileInDir *) elem1) -> fileTime < ((s_fileInDir *) elem2) -> fileTime) return -1; if (((s_fileInDir *) elem1) -> fileTime > ((s_fileInDir *) elem2) -> fileTime) return 1; return strcasecmp(((s_fileInDir *) elem1) -> fileName, ((s_fileInDir *) elem2) -> fileName); } static char *validExt[] = { "su", "mo", "tu", "we", "th", "fr", "sa" }; int isArcMail(char *fname) { char *p; int i; p=strrchr(fname, PATH_DELIM); if (p) p++; else p=fname; /* Amiga? */ for (i=0; i<8; i++) if (!isalnum(p[i])) break; if (i<8) { /* Amiga? */ for (i=0; i<4; i++) { if (!isdigit(*p++)) return 0; while (isdigit(*p)) p++; if (*p++ != '.') return 0; } } else { p += i; if (*p++ != '.') return 0; } for (i=0; id_name); #endif dummy = (char *) safe_malloc(dirNameLen + strlen(file->d_name) + 1); strcpy(dummy,directory); strcat(dummy,file->d_name); #if !defined(__UNIX__) #if defined(__TURBOC__) || defined(__DJGPP__) _dos_getfileattr(dummy, &fattrs); #elif defined(__MINGW32__) fattrs = (GetFileAttributes(dummy) & 0x2) ? _A_HIDDEN : 0; #else fattrs = file->d_attr; #endif if(fattrs & _A_HIDDEN) { nfree(dummy); } else #endif { nfiles++; files = (s_fileInDir *) safe_realloc(files,nfiles*sizeof(s_fileInDir)); (files[nfiles-1]).fileName = dummy; if(stat((files[nfiles-1]).fileName, &st)==0) { (files[nfiles-1]).fileTime = st.st_mtime; } else { /* FixMe - don't know what to set :( */ (files[nfiles-1]).fileTime = 0L; } } } closedir(dir); qsort (files, nfiles, sizeof(s_fileInDir), filesComparer); for ( filenum=0; filenum < nfiles; filenum++) { arcFile = pktFile = 0; dummy = (files[filenum]).fileName; #ifdef DEBUG_HPT w_log(LL_DEBUGV,"testing sorted %s\n", dummy); #endif if (!(pktFile = patimat(dummy+dirNameLen, "*.pkt") == 1)) if (isArcMail(dummy+dirNameLen)) arcFile = 1; if (pktFile || (arcFile && !config->noProcessBundles)) { rc = 3; /* nonsence, but compiler warns */ if (config->tossingExt != NULL && (newFileName=changeFileSuffix(dummy, config->tossingExt,1)) != NULL){ nfree(dummy); dummy = newFileName; newFileName=NULL; } if (pktFile) rc = processPkt(dummy, sec); else /* if (arcFile) */ rc = processArc(dummy, sec); if (rc>=1 && rc<=6) { w_log(LL_ERR, "Renaming pkt/arc to .%s",ext[rc]); newFileName=changeFileSuffix(dummy, ext[rc], 1); } else { if (rc!=7) remove(dummy); } } nfree(dummy); nfree(newFileName); } nfree(files); } void writeStatLog(void) { /* write personal mail statistic logfile if statlog is defined in config */ /* if the log file exists, the existing value is increased */ FILE *f = NULL; char buffer[256]; int len, x, statNetmail, statCC; statNetmail = statToss.netMail; /* number of just received netmails */ statCC = statToss.CC; /* number of just received personal echo mails */ /* if there are new personal mails and statLog is defined in config */ if (((statNetmail > 0) || (statCC > 0)) && (config->statlog != NULL)) { f = fopen(config->statlog, "r"); if (f != NULL) { /* and statLog file is readable */ w_log(LL_FILE,"toss.c:writeStatLog(): opened '%s' (\"r\" mode)",config->statlog); /* then read last personal mail counter and add to actual counter */ while(fgets(buffer,sizeof(buffer),f)) { len = strlen(buffer); for (x=0; x!=len; x++) { if (!strncasecmp(buffer+x, "netmail: ",9)) { /* netmail found */ statNetmail += atoi(buffer+9); } if (!strncasecmp(buffer+x, "CC: ",4)) { /* personal echomail (CC) found */ statCC += atoi(buffer+4); } } } fclose(f); } /* and write personal mail counter for netmails and echo mails */ f = fopen(config->statlog, "wt"); if (f != NULL) { w_log(LL_FILE,"toss.c:writeStatLog(): opened '%s' (\"wt\" mode)",config->statlog); if (statNetmail > 0) { fprintf(f, "netmail: %d\n", statNetmail); } if (statCC > 0) { fprintf(f, "CC: %d\n", statCC); } fclose(f); } } } void writeTossStatsToLog(void) { unsigned int i; float inMailsec, outMailsec, inKBsec; time_t diff = statToss.realTime; char logchar; if (statToss.pkts==0 && statToss.msgs==0) logchar='1'; else logchar='4'; if (diff == 0) diff = 1; inMailsec = ((float)(statToss.msgs)) / diff; outMailsec = ((float)(statToss.exported)) / diff; inKBsec = ((float)(statToss.inBytes)) / diff / 1024; w_log(logchar, "Statistics:"); w_log(logchar, " arc: % 5d netMail: % 4d echoMail: % 5d CC: % 5d", statToss.arch, statToss.netMail, statToss.echoMail, statToss.CC); w_log(logchar, " pkt's: % 5d dupe: % 4d passthru: % 5d exported: % 5d", statToss.pkts, statToss.dupes, statToss.passthrough, statToss.exported); w_log(logchar, " msgs: % 5d bad: % 4d saved: % 5d empty: % 5d", statToss.msgs, statToss.bad, statToss.saved, statToss.empty); w_log(logchar, " Input: % 8.2f mails/sec Output: % 8.2f mails/sec", inMailsec, outMailsec); w_log(logchar, " % 8.2f kb/sec", inKBsec); w_log(logchar, " % 8.2f kb total, processed in %8.3f seconds", ((float) statToss.inBytes / 1024), (float)statToss.realTime / 1000); /* write personal mail statistic logfile */ writeStatLog(); /* Now write areas summary */ w_log(logchar, "Areas summary:"); for (i = 0; i < config->netMailAreaCount; i++) if (config->netMailAreas[i].imported > 0) w_log(logchar, "netmail area %s - %d msgs", config->netMailAreas[i].areaName, config->netMailAreas[i].imported); if (config->dupeArea.imported) w_log(logchar, "dupe area %s - %d msgs", config->dupeArea.areaName, config->dupeArea.imported); if (config->badArea.imported) w_log(logchar, "bad area %s - %d msgs", config->badArea.areaName, config->badArea.imported); for (i = 0; i < config->echoAreaCount; i++) if (config->echoAreas[i].imported > 0) w_log(logchar, "echo area %s - %d msgs", config->echoAreas[i].areaName, config->echoAreas[i].imported); for (i = 0; i < config->localAreaCount; i++) if (config->localAreas[i].imported > 0) w_log(logchar, "local area %s - %d msgs", config->localAreas[i].areaName, config->localAreas[i].imported); } int find_old_arcmail(s_link *link, FILE *flo) { char *line = NULL, *bundle=NULL; ULONG len; unsigned as; while ((line = readLine(flo)) != NULL) { #ifndef __UNIX__ line = trimLine(line); #endif if ((*line=='^' || *line=='#') && isArcMail(line + 1)) { nfree(bundle); bundle = safe_strdup(line + 1); } nfree(line); } if (bundle == NULL) return 0; if (*bundle != '\000') { len = fsize(bundle); if (len != -1L) { if (link->arcmailSize!=0) as = link->arcmailSize; else if (config->defarcmailSize!=0) as = config->defarcmailSize; else as = 500; /* default 500 kb max */ if (len < as * 1024L) { link->packFile=(char*) safe_realloc(link->packFile,strlen(bundle)+1); strcpy(link->packFile,bundle); nfree(bundle); return 1; } } } nfree(bundle); return 0; } void arcmail(s_link *tolink) { char cmd[256], *pkt=NULL, *lastPathDelim = NULL, saveChar; int i, cmdexit, foa; FILE *flo = NULL; s_link *link = NULL; int startlink=0; int endlink = config->linkCount; hs_addr *aka; e_bundleFileNameStyle bundleNameStyle; if (tolink != NULL) { startlink = tolink - config->links; endlink = startlink + 1; } if (config->beforePack) { w_log(LL_EXEC, "beforePack: execute string \"%s\"", config->beforePack); if ((cmdexit = cmdcall(config->beforePack)) != 0) { w_log(LL_ERR, "exec failed, code %d", cmdexit); } } #ifdef DO_PERL perlbeforepack(); #endif for (i = startlink ; i < endlink; i++) { link = &(config->links[i]); /* only create floFile if we have mail for this link */ if (link->pktFile != NULL) { aka = SelectPackAka(link); if (needUseFileBoxForLinkAka(config,link,aka)) { if (!link->fileBox) link->fileBox = makeFileBoxNameAka (config,link,aka); _createDirectoryTree (link->fileBox); if (link->packFile == NULL) if (createPackFileName(link)) exit_hpt("Could not create new bundle!",1); if (link->packerDef != NULL) { fillCmdStatement(cmd, link->packerDef->call, link->packFile, link->pktFile, ""); w_log(LL_BUNDLE, "Packing for %s %s, %s > %s", aka2str(link->hisAka), link->name, get_filename(link->pktFile), get_filename(link->packFile)); w_log(LL_EXEC, "cmd: %s", cmd); if( stricmp(link->packerDef->call, "zipInternal") == 0 ) { #ifdef USE_HPT_ZLIB cmdexit = PackWithZlib(link->packFile, link->pktFile); #else cmdexit = -1; #endif }else cmdexit = cmdcall(cmd); if (cmdexit==0) remove(link->pktFile); else w_log(LL_ERR, "Error executing packer (errorlevel==%i)", cmdexit); } /* end packerDef */ else { /* there is no packer defined -> put pktFile into fileBox */ xstrcat(&pkt, link->fileBox); xstrcat(&pkt, link->pktFile + strlen(config->tempOutbound)); cmdexit = move_file(link->pktFile, pkt, 0); if (cmdexit==0) w_log(LL_BUNDLE, "Leave non-packed mail for %s %s, %s", aka2str(link->hisAka), link->name, get_filename(link->pktFile)); else w_log(LL_ERR, "error moving file for %s %s, %s->%s (errorlevel==%i)", aka2str(link->hisAka), link->name, link->pktFile, pkt, errno); nfree(pkt); } } else if (createOutboundFileNameAka(link,link->echoMailFlavour, FLOFILE, aka) == 0) { /* process if the link not busy, else do not create 12345678.?lo */ flo = fopen(link->floFile, "a+"); if (flo == NULL) w_log(LL_ERR, "Cannot open flo file %s", config->links[i].floFile); else { w_log(LL_FILE,"toss.c:arcmail(): opened '%s' (\"a+\" mode)",link->floFile); if (link->linkBundleNameStyle!=eUndef) bundleNameStyle=link->linkBundleNameStyle; else if (config->bundleNameStyle!=eUndef) bundleNameStyle=config->bundleNameStyle; else bundleNameStyle = eTimeStamp; if (link->packerDef != NULL) { /*there is a packer defined -> put packFile into flo */ /*if we are creating new arcmail bundle -> put packFile into flo*/ fseek(flo, 0L, SEEK_SET); foa = find_old_arcmail(link, flo); if (link->packFile == NULL) if (createPackFileName(link)) exit_hpt("Could not create new bundle!",1); fillCmdStatement(cmd, link->packerDef->call, link->packFile, link->pktFile, ""); w_log(LL_BUNDLE, "Packing for %s %s, %s > %s", aka2str(link->hisAka), link->name, get_filename(link->pktFile), get_filename(link->packFile)); w_log(LL_EXEC, "cmd: %s", cmd); if( stricmp(link->packerDef->call, "zipInternal") == 0 ) { #ifdef USE_HPT_ZLIB cmdexit = PackWithZlib(link->packFile, link->pktFile); #else cmdexit = -1; #endif } else { cmdexit = cmdcall(cmd); } if (cmdexit==0) { if (foa==0) { if (bundleNameStyle == eAddrDiff || bundleNameStyle == eAddrsCRC32 || bundleNameStyle == eAddrDiffAlways || bundleNameStyle == eAddrsCRC32Always || bundleNameStyle == eAmiga) fprintf(flo, "#%s\n", link->packFile); else fprintf(flo, "^%s\n", link->packFile); } remove(link->pktFile); } else w_log(LL_ERR, "Error executing packer (errorlevel==%i)", cmdexit); } /* end packerDef */ else { /* there is no packer defined -> put pktFile into flo */ lastPathDelim = strrchr(link->floFile, PATH_DELIM); /* change path of file to path of flofile */ saveChar = *(++lastPathDelim); *lastPathDelim = '\0'; xstrcat(&pkt, link->floFile); *lastPathDelim = saveChar; if (config->separateBundles) { if (bundleNameStyle==eAmiga) xscatprintf(&pkt, "%u.%u.%u.%u.sep%c", aka->zone, aka->net, aka->node, aka->point, PATH_DELIM); else { if (aka->point != 0) xscatprintf(&pkt,"%08x.sep%c", aka->point,PATH_DELIM); else xscatprintf(&pkt, "%04x%04x.sep%c", aka->net, aka->node, PATH_DELIM); } } xstrcat(&pkt, link->pktFile + strlen(config->tempOutbound)); cmdexit = move_file(link->pktFile, pkt, 0); if (cmdexit==0) { fprintf(flo, "^%s\n", pkt); w_log(LL_BUNDLE, "Leave non-packed mail for %s %s, %s", aka2str(link->hisAka), link->name, get_filename(link->pktFile)); } else w_log(LL_ERR, "error moving file for %s %s, %s->%s (errorlevel==%i)", aka2str(link->hisAka), link->name, link->pktFile, pkt, errno); nfree(pkt); } fclose(flo); } /* end flo */ nfree(link->floFile); remove(link->bsyFile); nfree(link->bsyFile); } /* end outboundFileNameCreated */ nfree(link->pktFile); nfree(link->packFile); } /* end pkt file */ } /* endfor */ return; } static int forwardedPkts = 0; int forwardPkt(const char *fileName, s_pktHeader *header, e_tossSecurity sec) { unsigned int i; s_link *link = NULL; char *newfn = NULL; for (i = 0 ; i < config->linkCount; i++) { if (addrComp(header->destAddr, config->links[i].hisAka) == 0) { /* we found a link to forward the pkt file to */ link = config->links+i; /* security checks */ if (link->forwardPkts==fOff) return 4; if ((link->forwardPkts==fSecure)&&(sec != secProtInbound)&&(sec != secLocalInbound)) return 4; /* as we have feature freeze currently, */ /* I enclose the following code with an ifdef ... */ newfn = makeUniqueDosFileName(config->tempOutbound, "pkt", config); if (move_file(fileName, newfn, 0) == 0) { /* save if exist */ w_log(LL_PKT, "Forwarding %s to %s as %s", fileName, config->links[i].name, newfn + strlen(config->tempOutbound)); nfree(newfn); forwardedPkts = 1; return 0; } else { w_log(LL_ERR, "Failure moving %s to %s (%s)", fileName, newfn, strerror(errno)); nfree(newfn); return 4; } } } w_log(LL_ERR, "Packet %s is not to us or our links",fileName); return 4; /* PKT is not for us and we did not find a link to forward the pkt file to */ } /* According to the specs, a .QQQ file does not have two leading zeros. This routine checks if the file is a .QQQ file, and if so, it appends the zeros and renames the file to .PKT. */ void fix_qqq(char *filename) { FILE *f = NULL; char buffer[2] = { '\0', '\0' }; size_t l = strlen(filename); char *newname=NULL; if (l > 3 && newname != NULL && toupper(filename[l-1]) == 'Q' && toupper(filename[l-2]) == 'Q' && toupper(filename[l-3]) == 'Q') { newname = safe_strdup(filename); strcpy(newname + l - 3, "pkt"); if (move_file(newname, filename, 0) == 0) { strcpy(filename, newname); if ((f = fopen(filename, "ab")) != NULL) { fwrite(buffer, 2, 1, f); fclose(f); } } else w_log(LL_ERR, "Failure moving %s to %s (%s)", newname, filename, strerror(errno)); nfree(newname); } } void tossTempOutbound(char *directory) { DIR *dir = NULL; FILE *pkt = NULL; struct dirent *file = NULL; char *dummy = NULL; s_pktHeader *header = NULL; s_link *link = NULL; size_t l; #ifdef NOSLASHES int dirNameLen; #endif if (directory==NULL) return; #ifdef NOSLASHES dirNameLen = strlen(directory); directory[dirNameLen-1]='\0'; #endif if (NULL == (dir = opendir(directory))) { printf("Can't open dir: %s!\n",directory); return; } #ifdef NOSLASHES directory[dirNameLen-1]='\\'; #endif while ((file = readdir(dir)) != NULL) { l = strlen(file->d_name); if (l > 4 && (stricmp(file->d_name + l - 4, ".pkt") == 0 || stricmp(file->d_name + l - 4, ".qqq") == 0)) { dummy = (char *) safe_malloc(strlen(directory)+l+1); strcpy(dummy, directory); strcat(dummy, file->d_name); fix_qqq(dummy); pkt = fopen(dummy, "rb"); if (pkt==NULL) continue; header = openPkt(pkt); if (header != NULL) { link = getLinkFromAddr (config, header->destAddr); } else { link = NULL; } if (link != NULL) { if (link->packFile == NULL) { if ( createPackFileName(link) ) exit_hpt("Could not create new bundle!",1); } nfree(link->pktFile); link->pktFile = dummy; fclose(pkt); arcmail(link); } else { nfree(dummy); w_log(LL_ERR, "found non packed mail without matching link in tempOutbound"); fclose(pkt); } } } closedir(dir); return; } void writeImportLog(void) { unsigned int i; FILE *f = NULL; struct stat buf; if (config->importlog) { /* write importlog */ f = fopen(config->importlog, "a"); if (f != NULL) { for (i = 0; i < config->netMailAreaCount; i++) if (config->netMailAreas[i].imported > 0) fprintf(f, "%s\n", config->netMailAreas[i].areaName); for (i = 0; i < config->echoAreaCount; i++) if (config->echoAreas[i].imported > 0 && config->echoAreas[i].msgbType != MSGTYPE_PASSTHROUGH) fprintf(f, "%s\n", config->echoAreas[i].areaName); for (i = 0; i < config->localAreaCount; i++) if (config->localAreas[i].imported > 0) fprintf(f, "%s\n", config->localAreas[i].areaName); fclose(f); #ifdef __UNIX__ chown(config->importlog, config->loguid, config->loggid); if (config -> logperm != -1) chmod(config->importlog, config->logperm); #endif } else w_log(LL_ERR, "Could not open importlogfile"); /* remove empty importlog */ if (stat(config->importlog, &buf)==0) { if (buf.st_size==0) remove(config->importlog); } } } #define MAXOPEN_DEFAULT 512 #if defined(__OS2__) #define INCL_DOS /* From os2emx.h: ULONG DosSetMaxFH (ULONG ulCount); ULONG DosSetRelMaxFH (PLONG pulReqCount, PULONG pulCurMaxFH); */ static void setmaxopen(void) { ULONG cur = 0, add = 0; if (DosSetRelMaxFH(&add, &cur) == 0) if (cur>=maxopenpkt) return; if (DosSetMaxFH(maxopenpkt)) while (cur static void setmaxopen(void) { #ifdef RLIMIT_NOFILE struct rlimit rl; unsigned maxopenpkt = MAXOPEN_DEFAULT; if (getrlimit(RLIMIT_NOFILE, &rl) == 0) if (rl.rlim_cur >= MAXOPEN_DEFAULT) return; /* try to set max open */ rl.rlim_cur = rl.rlim_max; if (setrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_cur >= MAXOPEN_DEFAULT) return; rl.rlim_cur = rl.rlim_max = maxopenpkt; setrlimit(RLIMIT_NOFILE, &rl); if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { maxopenpkt = rl.rlim_cur; return; } #endif #else /* windows or unknown OS, just test */ static void setmaxopen(void) { #endif { int handles[MAXOPEN_DEFAULT]; ULONG i; for (i=0; ilocalInbound, secLocalInbound); processDir(config->protInbound, secProtInbound); processDir(config->inbound, secInbound); nfree(globalBuffer); /* free msg->text global buffer */ writeDupeFiles(); writeImportLog(); if (forwardedPkts) { tossTempOutbound(config->tempOutbound); forwardedPkts = 0; } /* write statToss to Log */ writeTossStatsToLog(); tossTempOutbound(config->tempOutbound); /* create flag for netmail trackers */ if (config->netmailFlag && statToss.netMail) { if (NULL == (f = fopen(config->netmailFlag,"a"))) w_log(LL_ERR, "Could not create netmail flag: %s", config->netmailFlag); else { w_log(LL_FLAG, "Created netmail flag: %s", config->netmailFlag); fclose(f); } } w_log(LL_STOP, "End tossing"); } int packBadArea(HMSG hmsg, XMSG xmsg, char force) { int rc = 0; s_message msg; s_area *echo = &(config -> badArea); hs_addr pktOrigAddr; char *ptmp = NULL, *line = NULL, *areaName = NULL, *area=NULL, noexp=0; s_link *link = NULL; makeMsg(hmsg, xmsg, &msg, &(config->badArea), 2); memset(&pktOrigAddr,'\0',sizeof(hs_addr)); statToss.msgs++; /* really processed one more msg */ /* deleting valet string - "FROM:" and "REASON:" */ ptmp = msg.text; while ((line = strchr(ptmp, '\r')) != NULL) { /* Temporary make it \0 terminated string */ *line = '\000'; if (strncmp(ptmp, "FROM: ", 6) == 0 || strncmp(ptmp, "REASON: ", 8) == 0 || strncmp(ptmp, "AREANAME: ", 10) == 0) { /* It's from address */ if (*ptmp == 'F') string2addr(ptmp + 6, &pktOrigAddr); /* Don't export to links */ if (*ptmp == 'R') { if (strstr(ptmp, "MSGAPIERR: ")!=NULL) noexp=1; } /* Cut this kludges */ if (*ptmp=='A') { if (area==NULL) { echo = getArea(config, ptmp+10); xstrcat(&area, ptmp+10); } memmove(ptmp, line+1, strlen(line+1)+1); break; } else { memmove(ptmp, line+1, strlen(line+1)+1); continue; } } else { if ((strncmp(ptmp, "AREA:", 5)==0 || strncmp(ptmp, "\001AREA:", 6)==0) && area==NULL) { /* translating name of the area to uppercase */ strUpper(ptmp); areaName = (*ptmp!='\001') ? ptmp+5 : ptmp+6; /* if the areaname begins with a space */ while (*areaName == ' ') areaName++; echo = getArea(config, areaName); xstrcat(&area, areaName); }; ptmp = line+1; }; *line = '\r'; } if (echo == &(config->badArea)) { link = getLinkFromAddr(config, pktOrigAddr); if (link && link->autoAreaCreate!=0 && area) { if (0 == autoCreate(area, pktOrigAddr, NULL)) echo = getArea(config, area); } } nfree(area); if (echo == &(config->badArea)) { freeMsgBuffers(&msg); return rc; } if (checkAreaLink(echo, pktOrigAddr, 0) == 0 || force) { if (dupeDetection(echo, msg)==1 || noexp) { /* no dupe or toss whithout export to links */ if (config->carbonCount != 0) carbonCopy(&msg, NULL, echo); echo->imported++; /* area has got new messages */ #ifdef ADV_STAT if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stNORM, msg.textLength); #endif if (echo->msgbType != MSGTYPE_PASSTHROUGH) { rc = putMsgInArea(echo, &msg,1, 0); statToss.saved += rc; } else { statToss.passthrough++; rc = 1; /* passthrough always work */ } if (noexp==0) { /* recode & export to links */ /* recoding from internal to transport charSet */ if (config->outtab) { if (msg.recode & REC_HDR) { recodeToTransportCharset((CHAR*)msg.fromUserName); recodeToTransportCharset((CHAR*)msg.toUserName); recodeToTransportCharset((CHAR*)msg.subjectLine); msg.recode &= ~REC_HDR; } if (msg.recode & REC_TXT) { recodeToTransportCharset((CHAR*)msg.text); msg.recode &= ~REC_TXT; } } if (echo->downlinkCount > 0) { forwardMsgToLinks(echo, &msg, pktOrigAddr); } } } else { /* msg is dupe */ if (echo->dupeCheck == dcMove) { rc = putMsgInArea(&(config->dupeArea), &msg, 0, 0); } else rc = 1; /* dupeCheck del */ if (rc) config->dupeArea.imported++; #ifdef ADV_STAT if (config->advStatisticsFile != NULL) put_stat(echo, &pktOrigAddr, stDUPE, 0); #endif } } else rc = 0; freeMsgBuffers(&msg); return rc; } void tossFromBadArea(char force) { HAREA area; HMSG hmsg; XMSG xmsg; dword highestMsg, i; int delmsg; area = MsgOpenArea((UCHAR *) config->badArea.fileName, MSGAREA_NORMAL, (word)(config->badArea.msgbType|MSGTYPE_ECHO)); if (area != NULL) { w_log(LL_START, "Scanning area: %s", config->badArea.areaName); highestMsg = MsgGetNumMsg(area); for (i=1; i<=highestMsg; highestMsg--) { hmsg = MsgOpenMsg(area, MOPEN_RW, i); if (hmsg == NULL) continue; /* msg# does not exist */ MsgReadMsg(hmsg, &xmsg, 0, 0, NULL, 0, NULL); delmsg = packBadArea(hmsg, xmsg, force); MsgCloseMsg(hmsg); if (delmsg) MsgKillMsg(area, i); else { i++; highestMsg++; } } MsgCloseArea(area); closeOpenedPkt(); writeDupeFiles(); writeImportLog(); w_log(LL_STAT, "Statistics"); w_log(LL_STAT, " scanned: % 5d saved: % 7d CC: % 2d", statToss.msgs, statToss.saved, statToss.CC); w_log(LL_STAT, " exported: % 4d passthru: % 4d", statToss.exported, statToss.passthrough); tossTempOutbound(config->tempOutbound); } else w_log(LL_ERR, "Could not open %s", config->badArea.fileName); }