/***************************************************************************** * HPT --- FTN NetMail/EchoMail Tosser ***************************************************************************** * Copyright (C) 1997-2000 * * 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 * * Hash Dupe and other typeDupeBase (C) 2000 * * Alexander Vernigora * * Fido: 2:4625/69 * Internet: alexv@vsmu.vinnica.ua * * Yunosty 79, app.13 * 287100 Vinnitsa * Ukraine * * 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: dupe.c,v 1.64 2002/06/17 11:54:01 stas Stab $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include FILE *fDupe; UINT32 DupeCountInHeader, maxTimeLifeDupesInArea; s_dupeMemory *CommonDupes=NULL; char *createDupeFileName(s_area *area) { char *name=NULL, *ptr, *retname=NULL; // w_log(LL_FUNC,"dupe.c::createDupeFileName()"); if (!area->DOSFile) {/* if (area->fileName) xstrcat(&name, (ptr = strrchr(area->fileName,PATH_DELIM)) ? ptr+1 : area->fileName); else*/ name = makeMsgbFileName(config, area->areaName); } else { if (area->fileName) xstrcat(&name, (ptr = strrchr(area->fileName,PATH_DELIM)) ? ptr+1 : area->fileName); // else xstrcat(&name, "passthru"); else xscatprintf(&name, "%X", strcrc32(area->areaName,0xFFFFFFFFUL) ); } switch (config->typeDupeBase) { case hashDupes: xstrcat(&name,".dph"); break; case hashDupesWmsgid: xstrcat(&name,".dpd"); break; case textDupes: xstrcat(&name,".dpt"); break; case commonDupeBase: break; } if (config->areasFileNameCase == eUpper) name = strUpper(name); else name = strLower(name); xstrscat(&retname, config->dupeHistoryDir, name, NULL); nfree(name); // w_log(LL_FUNC,"dupe.c::createDupeFileName() OK (return '%s')",retname); return retname; } /* int compareEntriesBlank(char *e1, char *e2) { int rc=1; unused(e1); unused(e2); return rc; } */ int compareEntries(char *p_e1, char *p_e2) { const s_textDupeEntry *atxt, *btxt; const s_hashDupeEntry *ahash, *bhash; const s_hashMDupeEntry *ahashM, *bhashM; int rc = 1; const void *e1 = (const void *)p_e1, *e2 = (const void *)p_e2; switch (config->typeDupeBase) { case hashDupes: ahash = e1; bhash = e2; if (ahash->CrcOfDupe == bhash->CrcOfDupe) rc = 0; else if (ahash->CrcOfDupe > bhash->CrcOfDupe) rc = 1; else rc = -1; break; case hashDupesWmsgid: ahashM = e1; bhashM = e2; if (ahashM->CrcOfDupe == bhashM->CrcOfDupe) rc = strcmp(ahashM->msgid, bhashM->msgid); else if (ahashM->CrcOfDupe > bhashM->CrcOfDupe) rc = 1; else rc = -1; break; case textDupes: atxt = e1; btxt = e2; rc = strcmp(atxt->from, btxt->from); if (rc == 0) rc = strcmp(atxt->to, btxt->to); if (rc == 0) rc = strcmp(atxt->subject, btxt->subject); if (rc == 0) rc = strcmp(atxt->msgid, btxt->msgid); break; case commonDupeBase: ahash = e1; bhash = e2; if (ahash->CrcOfDupe == bhash->CrcOfDupe) rc=0; else if (ahash->CrcOfDupe > bhash->CrcOfDupe) rc = 1; else rc = -1; break; } return rc; } int writeEntry(char *p_entry) { const s_textDupeEntry *entxt; const s_hashDupeEntry *enhash; const s_hashMDupeEntry *enhashM; UINT32 diff=0; time_t currtime; const void *entry = (const void *)p_entry; currtime = time(NULL); switch (config->typeDupeBase) { case hashDupes: enhash = entry; if ( (diff = currtime - enhash->TimeStampOfDupe) < maxTimeLifeDupesInArea) { fwrite(enhash, sizeof(s_hashDupeEntry), 1, fDupe); DupeCountInHeader++; } break; case hashDupesWmsgid: enhashM = entry; if ( (diff = currtime - enhashM->TimeStampOfDupe) < maxTimeLifeDupesInArea) { fwrite(enhashM, sizeof(time_t)+sizeof(UINT32), 1, fDupe); if ((enhashM->msgid != NULL)&&(0 < strlen(enhashM->msgid))) { fputc(strlen(enhashM->msgid), fDupe); fputs(enhashM->msgid, fDupe); } else fputc(0, fDupe); DupeCountInHeader++; } break; case textDupes: entxt = entry; if ( (diff = currtime - entxt->TimeStampOfDupe) < maxTimeLifeDupesInArea) { fwrite(entxt, sizeof(time_t), 1, fDupe); if ((entxt->msgid != NULL)&&(0 < strlen(entxt->from))) { fputc(strlen(entxt->from), fDupe); fputs(entxt->from, fDupe); } else fputc(0, fDupe); if ((entxt->msgid != NULL)&&(0 < strlen(entxt->to))) { fputc(strlen(entxt->to), fDupe); fputs(entxt->to, fDupe); } else fputc(0, fDupe); if ((entxt->msgid != NULL)&&(0 < strlen(entxt->subject))) { fputc(strlen(entxt->subject), fDupe); fputs(entxt->subject, fDupe); } else fputc(0, fDupe); if ((entxt->msgid != NULL)&&(0 < strlen(entxt->msgid))) { fputc(strlen(entxt->msgid), fDupe); fputs(entxt->msgid, fDupe); } else fputc(0, fDupe); DupeCountInHeader++; } break; case commonDupeBase: enhash = entry; if ( (diff = currtime - enhash->TimeStampOfDupe) < maxTimeLifeDupesInArea) { fwrite(enhash, sizeof(s_hashDupeEntry), 1, fDupe); DupeCountInHeader++; } break; } return 1; } int deleteEntry(char *entry) { const s_textDupeEntry *entxt; const s_hashDupeEntry *enhash; const s_hashMDupeEntry *enhashM; switch (config->typeDupeBase) { case hashDupes: enhash = (s_hashDupeEntry *)entry; free((s_hashDupeEntry*) enhash); break; case hashDupesWmsgid: enhashM = (s_hashMDupeEntry *)entry; free((s_hashMDupeEntry*)enhashM->msgid); free((s_hashMDupeEntry*)enhashM); break; case textDupes: entxt = (s_textDupeEntry *)entry; free((s_textDupeEntry*)entxt->to); free((s_textDupeEntry*)entxt->from); free((s_textDupeEntry*)entxt->subject); free((s_textDupeEntry*)entxt->msgid); free((s_textDupeEntry*)entxt); break; case commonDupeBase: enhash = (s_hashDupeEntry *)entry; free((s_hashDupeEntry*)enhash); break; } return 1; } void doReading(FILE *f, s_dupeMemory *mem) { s_textDupeEntry *entxt; s_hashDupeEntry *enhash; s_hashMDupeEntry *enhashM; UCHAR length; UINT32 i; time_t timedupe; // read Number Of Dupes from dupefile fread(&DupeCountInHeader, sizeof(UINT32), 1, f); // process all dupes for (i = 0; i < DupeCountInHeader; i++) { if (feof(f)) break; switch (config->typeDupeBase) { case hashDupes: enhash = (s_hashDupeEntry*) safe_malloc(sizeof(s_hashDupeEntry)); fread(enhash, sizeof(s_hashDupeEntry), 1, f); tree_add(&(mem->avlTree), /*compareEntriesBlank*/ compareEntries, (char *) enhash, deleteEntry); break; case hashDupesWmsgid: enhashM = (s_hashMDupeEntry*) safe_malloc(sizeof(s_hashMDupeEntry)); fread(enhashM, sizeof(time_t)+sizeof(UINT32), 1, f); if ((length = (UCHAR)getc(f)) > 0) { /* no EOF check :-( */ enhashM->msgid = safe_malloc(length+1); fread((UCHAR*)enhashM->msgid, length, 1, f); enhashM->msgid[length]='\0'; } else enhashM->msgid = NULL; tree_add(&(mem->avlTree), /*compareEntriesBlank*/ compareEntries, (char *) enhashM, deleteEntry); break; case textDupes: entxt = (s_textDupeEntry*) safe_malloc(sizeof(s_textDupeEntry)); fread(&timedupe, sizeof(time_t), 1, f); entxt->TimeStampOfDupe=timedupe; if ((length = (UCHAR)getc(f)) > 0) { /* no EOF check :-( */ entxt->from = safe_malloc(length+1); fread((UCHAR*)entxt->from, length, 1, f); entxt->from[length]='\0'; } else entxt->from = NULL; if ((length = (UCHAR) getc(f)) > 0) { /* no EOF check :-( */ entxt->to = safe_malloc(length+1); fread((UCHAR*)entxt->to, length, 1, f); entxt->to[length]='\0'; } else entxt->to = NULL; if ((length = (UCHAR)getc(f)) > 0) { /* no EOF check :-( */ entxt->subject = safe_malloc(length+1); fread((UCHAR*)entxt->subject, length, 1, f); entxt->subject[length]='\0'; } else entxt->subject = NULL; if ((length = (UCHAR)getc(f)) > 0) { /* no EOF check :-( */ entxt->msgid = safe_malloc(length+1); fread((UCHAR*)entxt->msgid, length, 1, f); entxt->msgid[length]='\0'; } else entxt->msgid = NULL; tree_add(&(mem->avlTree), /*compareEntriesBlank*/ compareEntries, (char *) entxt, deleteEntry); break; case commonDupeBase: enhash = (s_hashDupeEntry*) safe_malloc(sizeof(s_hashDupeEntry)); fread(enhash, sizeof(s_hashDupeEntry), 1, f); tree_add(&(mem->avlTree), /*compareEntriesBlank*/ compareEntries, (char *) enhash, deleteEntry); break; } } } s_dupeMemory *readDupeFile(s_area *area) { FILE *f; char *fileName=NULL; s_dupeMemory *dupeMemory; dupeMemory = safe_malloc(sizeof(s_dupeMemory)); tree_init(&(dupeMemory->avlTree)); if (config->typeDupeBase!=commonDupeBase) { fileName = createDupeFileName(area); w_log(LL_DUPE, "Reading dupes of %s", area->areaName); } else { xstrscat(&fileName, config->dupeHistoryDir, "hpt_base.dpa", NULL); w_log(LL_DUPE, "Reading dupes from %s", fileName); } f = fopen(fileName, "rb"); if (f != NULL) { w_log(LL_FILE,"dupe.c:readDupeFile(): opened %s (\"rb\" mode)",fileName); // readFile doReading(f, dupeMemory); fclose(f); } else { if (fexist(fileName)) w_log(LL_ERR, "Error reading dupe base: %s", fileName); else if( errno != ENOENT) w_log(LL_ERR, "Dupe base '%s' read error: %s", fileName, strerror(errno) ); } nfree(fileName); return dupeMemory; } int createDupeFile(s_area *area, char *name, s_dupeMemory DupeEntries) { FILE *f; // w_log(LL_SRCLINE,"dupe.c:%u:createDupeFile() name='%s'", __LINE__, name); f = fopen(name, "wb"); if (f!= NULL) { w_log(LL_FILE,"dupe.c:createDupeFile(): opened %s (\"wb\" mode)",name); if (config->typeDupeBase!=commonDupeBase) maxTimeLifeDupesInArea=area->dupeHistory*86400; else maxTimeLifeDupesInArea=config->areasMaxDupeAge*86400; DupeCountInHeader = 0; fwrite(&DupeCountInHeader, sizeof(UINT32), 1, f); fDupe = f; tree_trav(&(DupeEntries.avlTree), writeEntry); fDupe = NULL; // writeDupeFileHeader if (DupeCountInHeader>0) { fseek(f, 0, SEEK_SET); fwrite(&DupeCountInHeader, sizeof(UINT32), 1, f); fclose(f); // for 1 save commonDupeBase if (config->typeDupeBase==commonDupeBase) freeDupeMemory(area); } else { fclose(f); remove (name); } return 0; } else return 1; } int writeToDupeFile(s_area *area) { char *fileName=NULL; s_dupeMemory *dupes; int rc = 0; if (area->dupeCheck == dcOff) return rc; if (config->typeDupeBase!=commonDupeBase) { dupes = area->dupes; fileName = createDupeFileName(area); } else { dupes = CommonDupes; xstrscat(&fileName, config->dupeHistoryDir, "hpt_base.dpa", NULL); } if (dupes != NULL) { if (tree_count(&(dupes->avlTree)) > 0) { rc = createDupeFile(area, fileName, *dupes); } } nfree(fileName); return rc; } void freeDupeMemory(s_area *area) { s_dupeMemory *dupes; if (area->dupeCheck == dcOff) return; if (config->typeDupeBase != commonDupeBase) dupes = area -> dupes; else dupes = CommonDupes; if (dupes != NULL) { tree_mung(&(dupes -> avlTree), deleteEntry); if (config->typeDupeBase != commonDupeBase) { nfree(area -> dupes); } else { nfree(CommonDupes); } }; } int dupeDetection(s_area *area, const s_message msg) { s_dupeMemory *Dupes = area->dupes; s_textDupeEntry *entxt; s_hashDupeEntry *enhash; s_hashMDupeEntry *enhashM; char *str, *str1; int nRet = 0; w_log(LL_FUNC,"dupe.c::dupeDetection() begin"); if (area->dupeCheck == dcOff) return 1; // no dupeCheck return 1 "no dupe" if ((str=(char*)GetCtrlToken((byte*)msg.text, (byte*)"MSGID:"))==NULL) { if (msg.text) xscatprintf (&str, "MSGID: %08lx",strcrc32(msg.text, 0xFFFFFFFFL)); else return 1; // without msg.text - message is empty, no dupeCheck } // test if dupeDatabase is already read if (config->typeDupeBase != commonDupeBase) { if (area->dupes == NULL) { Dupes = area->dupes = readDupeFile(area); //read Dupes } } else { if (CommonDupes == NULL) CommonDupes = readDupeFile(area); //read Dupes } switch (config->typeDupeBase) { case hashDupes: enhash = safe_malloc(sizeof(s_hashDupeEntry)); str1 = safe_malloc(strlen(msg.fromUserName)+strlen(msg.toUserName)+strlen(msg.subjectLine)+strlen(str)); strcpy(str1, msg.fromUserName); strcat(str1, msg.toUserName); strcat(str1, msg.subjectLine); strcat(str1, str+7); nfree(str); enhash->CrcOfDupe = strcrc32(str1, 0xFFFFFFFFL); enhash->TimeStampOfDupe = time (NULL); nfree(str1); nRet = tree_add(&(Dupes->avlTree), compareEntries, (char *) enhash, deleteEntry); break; case hashDupesWmsgid: enhashM = safe_malloc(sizeof(s_hashMDupeEntry)); str1 = safe_malloc(strlen(msg.fromUserName)+strlen(msg.toUserName)+strlen(msg.subjectLine)+strlen(str)); strcpy(str1, msg.fromUserName); strcat(str1, msg.toUserName); strcat(str1, msg.subjectLine); strcat(str1, str+7); enhashM->msgid = safe_malloc(strlen(str)+1-7); strcpy(enhashM->msgid, str+7); nfree(str); enhashM->CrcOfDupe = strcrc32(str1, 0xFFFFFFFFL); enhashM->TimeStampOfDupe = time (NULL); nfree(str1); nRet = tree_add(&(Dupes->avlTree), compareEntries, (char *) enhashM, deleteEntry); break; case textDupes: entxt = safe_malloc(sizeof(s_textDupeEntry)); entxt->TimeStampOfDupe = time (NULL); entxt->from = safe_malloc(strlen(msg.fromUserName)+2); if (0==strlen(msg.fromUserName)) strcpy(entxt->from," "); else strcpy(entxt->from, msg.fromUserName); entxt->to = safe_malloc(strlen(msg.toUserName)+2); if (0==strlen(msg.toUserName)) strcpy(entxt->to," "); else strcpy(entxt->to, msg.toUserName); entxt->subject = safe_malloc(strlen(msg.subjectLine)+2); if (0==strlen(msg.subjectLine)) strcpy(entxt->subject," "); else strcpy(entxt->subject, msg.subjectLine); entxt->msgid = safe_malloc(strlen(str)+2-7); strcpy(entxt->msgid, str+7); nfree(str); nRet = tree_add(&(Dupes->avlTree), compareEntries, (char *) entxt, deleteEntry); break; case commonDupeBase: enhash = safe_malloc(sizeof(s_hashDupeEntry)); str1 = safe_malloc(strlen(msg.fromUserName)+strlen(msg.toUserName)+strlen(msg.subjectLine)+strlen(area->areaName)+strlen(str)+10); strcpy(str1, area->areaName); strcat(str1, msg.fromUserName); strcat(str1, msg.toUserName); strcat(str1, msg.subjectLine); strcat(str1, str+7); nfree(str); enhash->CrcOfDupe = strcrc32(str1, 0xFFFFFFFFL); enhash->TimeStampOfDupe = time (NULL); nfree(str1); nRet = tree_add(&(CommonDupes->avlTree), compareEntries, (char *) enhash, deleteEntry); break; } w_log(LL_FUNC,"dupe.c::dupeDetection() end nRet = %d", nRet); return nRet; }