1 /*****************************************************************************
2  * HPT --- FTN NetMail/EchoMail Tosser
3  *****************************************************************************
4  * Copyright (C) 1997-2000
5  *
6  * Matthias Tichy
7  *
8  * Fido:     2:2433/1245 2:2433/1247 2:2432/605.14
9  * Internet: mtt@tichy.de
10  *
11  * Grimmestr. 12         Buchholzer Weg 4
12  * 33098 Paderborn       40472 Duesseldorf
13  * Germany               Germany
14  *
15  * Hash Dupe and other typeDupeBase (C) 2000
16  *
17  * Alexander Vernigora
18  *
19  * Fido:     2:4625/69
20  * Internet: alexv@vsmu.vinnica.ua
21  *
22  * Yunosty 79, app.13
23  * 287100 Vinnitsa
24  * Ukraine
25  *
26  * This file is part of HPT.
27  *
28  * HPT is free software; you can redistribute it and/or modify it
29  * under the terms of the GNU General Public License as published by the
30  * Free Software Foundation; either version 2, or (at your option) any
31  * later version.
32  *
33  * HPT is distributed in the hope that it will be useful, but
34  * WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
36  * General Public License for more details.
37  *
38  * You should have received a copy of the GNU General Public License
39  * along with HPT; see the file COPYING.  If not, write to the Free
40  * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
41  *****************************************************************************
42  * $Id$
43  */
44 #include <string.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <time.h>
48 #include <ctype.h>
49 #include <errno.h>
50 
51 #include <pkt.h>
52 #include <areafix/areafix.h>
53 #include <global.h>
54 
55 #include <huskylib/compiler.h>
56 #include <huskylib/huskylib.h>
57 #include <huskylib/cvtdate.h>
58 #include <huskylib/unused.h>
59 
60 #include <smapi/msgapi.h>
61 #include <dupe.h>
62 
63 #include <fidoconf/common.h>
64 #include <huskylib/xstr.h>
65 #include <huskylib/crc.h>
66 
67 
68 FILE *fDupe;
69 
70 UINT32  DupeCountInHeader, maxTimeLifeDupesInArea;
71 s_dupeMemory *CommonDupes=NULL;
72 
73 #define MSGIDPOS        7
74 #define HASHBUFSIZE     3*XMSG_TO_SIZE /* msgid len */ + AREANAMELEN
75 static char hashBuf [HASHBUFSIZE];
76 
77 static time_t TimeStamp;
78 
createDupeFileName(s_area * area)79 char *createDupeFileName(s_area *area) {
80     char *name=NULL, *ptr, *retname=NULL;
81 
82 
83     if (!area->DOSFile) {
84         name = makeMsgbFileName(config, area->areaName);
85     } else {
86         if (area->fileName)
87             xstrcat(&name, ((ptr = strrchr(area->fileName,PATH_DELIM)) != NULL)
88                         ? ptr+1 : area->fileName);
89         else xscatprintf(&name, "%X", strcrc32(area->areaName,0xFFFFFFFFUL) );
90     }
91 
92     switch (config->typeDupeBase) {
93     case hashDupes:
94         xstrcat(&name,".dph");
95         break;
96     case hashDupesWmsgid:
97         xstrcat(&name,".dpd");
98         break;
99     case textDupes:
100         xstrcat(&name,".dpt");
101         break;
102     case commonDupeBase:
103         break;
104     }
105 
106     if (config->areasFileNameCase == eUpper)
107         name = strUpper(name);
108     else
109         name = strLower(name);
110 
111     xstrscat(&retname, config->dupeHistoryDir, name, NULLP);
112     nfree(name);
113 
114     return retname;
115 }
116 
117 
compareEntries(char * p_e1,char * p_e2)118 int compareEntries(char *p_e1, char *p_e2) {
119     const s_textDupeEntry  *atxt,   *btxt;
120     const s_hashDupeEntry  *ahash,  *bhash;
121     const s_hashMDupeEntry *ahashM, *bhashM;
122     int rc = 0;
123     const void *e1 = (const void *)p_e1, *e2 = (const void *)p_e2;
124 
125     switch (config->typeDupeBase) {
126     case hashDupes:
127         ahash = e1; bhash = e2;
128         if (ahash->CrcOfDupe > bhash->CrcOfDupe)
129             rc =  1;
130         else if (ahash->CrcOfDupe < bhash->CrcOfDupe)
131             rc = -1;
132         else
133             rc =  0;
134         break;
135 
136     case hashDupesWmsgid:
137         ahashM = e1; bhashM = e2;
138         if (ahashM->CrcOfDupe == bhashM->CrcOfDupe)
139             rc = sstrcmp(ahashM->msgid, bhashM->msgid);
140         else if (ahashM->CrcOfDupe > bhashM->CrcOfDupe)
141             rc = 1;
142         else
143             rc = -1;
144         break;
145 
146     case textDupes:
147         atxt = e1; btxt = e2;
148         rc = sstrcmp(atxt->msgid, btxt->msgid);
149         break;
150 
151     case commonDupeBase:
152         ahash = e1; bhash = e2;
153         if (ahash->CrcOfDupe > bhash->CrcOfDupe)
154             rc =  1;
155         else if (ahash->CrcOfDupe < bhash->CrcOfDupe)
156             rc = -1;
157         else
158             rc =  0;
159         break;
160     }
161 
162     return rc;
163 }
164 
writeEntry(char * p_entry)165 int writeEntry(char *p_entry) {
166    const s_textDupeEntry  *entxt;
167    const s_hashDupeEntry  *enhash;
168    const s_hashMDupeEntry *enhashM;
169    UINT32 diff=0;
170    time_t currtime;
171    const void *entry = (const void *)p_entry;
172 
173    currtime = TimeStamp;
174 
175    switch (config->typeDupeBase) {
176       case hashDupes:
177            enhash = entry;
178            if ( (diff = currtime - enhash->TimeStampOfDupe) < maxTimeLifeDupesInArea) {
179               fwrite(enhash, sizeof(s_hashDupeEntry), 1, fDupe);
180               DupeCountInHeader++;
181            }
182    	   break;
183 
184       case hashDupesWmsgid:
185            enhashM = entry;
186            if ( (diff = currtime - enhashM->TimeStampOfDupe) < maxTimeLifeDupesInArea) {
187               fwrite(enhashM, sizeof(time_t)+sizeof(UINT32), 1, fDupe);
188               if ((enhashM->msgid != NULL)&&(0 < strlen(enhashM->msgid))) {
189                  fputc(strlen(enhashM->msgid), fDupe);
190                  fputs(enhashM->msgid, fDupe);
191               }
192               else fputc(0, fDupe);
193               DupeCountInHeader++;
194            }
195   	   break;
196 
197       case textDupes:
198            entxt = entry;
199            if ( (diff = currtime - entxt->TimeStampOfDupe) < maxTimeLifeDupesInArea) {
200               fwrite(entxt, sizeof(time_t), 1, fDupe);
201               /* write zero length of this field. left for backward compatibility
202               if ((entxt->msgid != NULL)&&(0 < strlen(entxt->from))) {
203                  fputc(strlen(entxt->from), fDupe);
204                  fputs(entxt->from, fDupe);
205               }
206               else
207               */
208               fputc(0, fDupe);
209               /* write zero length of this field. left for backward compatibility
210               if ((entxt->msgid != NULL)&&(0 < strlen(entxt->to))) {
211                  fputc(strlen(entxt->to), fDupe);
212                  fputs(entxt->to, fDupe);
213               }
214               else
215               */
216               fputc(0, fDupe);
217               /* write zero length of this field. left for backward compatibility
218               if ((entxt->msgid != NULL)&&(0 < strlen(entxt->subject))) {
219                  fputc(strlen(entxt->subject), fDupe);
220                  fputs(entxt->subject, fDupe);
221               }
222               else
223               */
224               fputc(0, fDupe);
225               if ((entxt->msgid != NULL)&&(0 < strlen(entxt->msgid))) {
226                  fputc(strlen(entxt->msgid), fDupe);
227                  fputs(entxt->msgid, fDupe);
228               }
229               else fputc(0, fDupe);
230               DupeCountInHeader++;
231            }
232  	   break;
233 
234       case commonDupeBase:
235            enhash = entry;
236            if ( (diff = currtime - enhash->TimeStampOfDupe) < maxTimeLifeDupesInArea) {
237               fwrite(enhash, sizeof(s_hashDupeEntry), 1, fDupe);
238               DupeCountInHeader++;
239            }
240            break;
241    }
242 
243    return 1;
244 }
245 
deleteEntry(char * entry)246 int deleteEntry(char *entry) {
247     if(entry)
248     {
249         s_textDupeEntry  *entxt;
250         s_hashDupeEntry  *enhash;
251         s_hashMDupeEntry *enhashM;
252 
253         switch (config->typeDupeBase) {
254         case hashDupes:
255             enhash = (s_hashDupeEntry *)entry;
256             nfree(enhash);
257             break;
258 
259         case hashDupesWmsgid:
260             enhashM = (s_hashMDupeEntry *)entry;
261             nfree(enhashM->msgid);
262             nfree(enhashM);
263             break;
264 
265         case textDupes:
266             entxt = (s_textDupeEntry *)entry;
267             nfree(entxt->msgid);
268             nfree(entxt);
269             break;
270 
271         case commonDupeBase:
272             enhash = (s_hashDupeEntry *)entry;
273             nfree(enhash);
274             break;
275         }
276     }
277     return 1;
278 }
279 
doReading(FILE * f,s_dupeMemory * mem)280 void doReading(FILE *f, s_dupeMemory *mem)
281 {
282     s_textDupeEntry  *entxt;
283     s_hashDupeEntry  *enhash;
284     s_hashMDupeEntry *enhashM;
285     UCHAR   length;
286     UINT32 i;
287     time_t timedupe;
288 
289     /*  read Number Of Dupes from dupefile */
290     fread(&DupeCountInHeader, sizeof(UINT32), 1, f);
291 
292     /*  process all dupes */
293     for (i = 0; i < DupeCountInHeader; i++) {
294         if (feof(f)) break;
295 
296         switch (config->typeDupeBase) {
297         case hashDupes:
298             enhash = (s_hashDupeEntry*) safe_malloc(sizeof(s_hashDupeEntry));
299             fread(enhash, sizeof(s_hashDupeEntry), 1, f);
300             tree_add(&(mem->avlTree), compareEntries, (char *) enhash, deleteEntry);
301             break;
302 
303         case hashDupesWmsgid:
304             enhashM = (s_hashMDupeEntry*) safe_malloc(sizeof(s_hashMDupeEntry));
305             fread(enhashM, sizeof(time_t)+sizeof(UINT32), 1, f);
306             if ((length = (UCHAR)getc(f)) > 0) {  /* no EOF check :-( */
307                 enhashM->msgid = safe_malloc(length+1);
308                 fread((UCHAR*)enhashM->msgid, length, 1, f);
309                 enhashM->msgid[length]='\0';
310             } else enhashM->msgid = NULL;
311             tree_add(&(mem->avlTree), compareEntries, (char *) enhashM, deleteEntry);
312             break;
313 
314         case textDupes:
315 
316                 entxt = (s_textDupeEntry*) safe_malloc(sizeof(s_textDupeEntry));
317 
318                 fread(&timedupe, sizeof(time_t), 1, f);
319                 entxt->TimeStampOfDupe=timedupe;
320 
321                 if ((length = (UCHAR)getc(f)) > 0) { /* no EOF check :-( */
322                     fread(hashBuf, length, 1, f);
323                 }
324                 if ((length = (UCHAR) getc(f)) > 0) { /* no EOF check :-( */
325                     fread(hashBuf, length, 1, f);
326                 }
327                 if ((length = (UCHAR)getc(f)) > 0) { /* no EOF check :-( */
328                     fread(hashBuf, length, 1, f);
329                 }
330                 if ((length = (UCHAR)getc(f)) > 0) { /* no EOF check :-( */
331                     entxt->msgid = safe_malloc(length+1);
332                     fread((UCHAR*)entxt->msgid, length, 1, f);
333                     entxt->msgid[length]='\0';
334                 } else entxt->msgid = NULL;
335 
336                 if(entxt->msgid)
337                     tree_add(&(mem->avlTree), compareEntries, (char *) entxt, deleteEntry);
338                 break;
339 
340         case commonDupeBase:
341             enhash = (s_hashDupeEntry*) safe_malloc(sizeof(s_hashDupeEntry));
342             fread(enhash, sizeof(s_hashDupeEntry), 1, f);
343             tree_add(&(mem->avlTree), compareEntries, (char *) enhash, deleteEntry);
344             break;
345         }
346 
347 
348     }
349 }
350 
readDupeFile(s_area * area)351 s_dupeMemory *readDupeFile(s_area *area) {
352    FILE *f;
353    char *fileName=NULL;
354    s_dupeMemory *dupeMemory;
355 
356    TimeStamp = time (NULL);
357 
358    dupeMemory = safe_malloc(sizeof(s_dupeMemory));
359    tree_init(&(dupeMemory->avlTree),1);
360 
361    if (config->typeDupeBase!=commonDupeBase) {
362        fileName = createDupeFileName(area);
363        w_log(LL_DUPE, "Reading dupes of %s", area->areaName);
364    }
365    else {
366        xstrscat(&fileName, config->dupeHistoryDir, "hpt_base.dpa", NULLP);
367        w_log(LL_DUPE, "Reading dupes from %s", fileName);
368    }
369 
370    f = fopen(fileName, "rb");
371    if (f != NULL) { w_log(LL_FILE,"dupe.c:readDupeFile(): opened %s (\"rb\" mode)",fileName);
372        /*  readFile */
373        doReading(f, dupeMemory);
374        fclose(f);
375    } else {
376        if (fexist(fileName)) w_log(LL_ERR, "Error reading dupe base: %s", fileName);
377        else if( errno != ENOENT)
378          w_log(LL_ERR, "Dupe base '%s' read error: %s", fileName, strerror(errno) );
379    }
380 
381    nfree(fileName);
382 
383    return dupeMemory;
384 }
385 
386 
createDupeFile(s_area * area,char * name,s_dupeMemory DupeEntries)387 int createDupeFile(s_area *area, char *name, s_dupeMemory DupeEntries) {
388    FILE *f;
389 
390 /*    w_log(LL_SRCLINE,"dupe.c:%u:createDupeFile() name='%s'", __LINE__, name); */
391 
392    f = fopen(name, "wb");
393    if (f!= NULL) {
394        w_log(LL_FILE,"dupe.c:createDupeFile(): opened %s (\"wb\" mode)",name);
395        if (config->typeDupeBase!=commonDupeBase)
396           maxTimeLifeDupesInArea=area->dupeHistory*86400;
397        else
398           maxTimeLifeDupesInArea=config->areasMaxDupeAge*86400;
399 
400        DupeCountInHeader = 0;
401        fwrite(&DupeCountInHeader, sizeof(UINT32), 1, f);
402        fDupe = f;
403        tree_trav(&(DupeEntries.avlTree), writeEntry);
404        fDupe = NULL;
405 
406        /*  writeDupeFileHeader */
407        if (DupeCountInHeader>0) {
408           fseek(f, 0, SEEK_SET);
409           fwrite(&DupeCountInHeader, sizeof(UINT32), 1, f);
410           fclose(f);
411        /*  for 1 save commonDupeBase */
412        if (config->typeDupeBase==commonDupeBase)
413           freeDupeMemory(area);
414        }
415        else {
416           fclose(f);
417           remove (name);
418        }
419 
420        return 0;
421    } else return 1;
422 }
423 
424 
writeToDupeFile(s_area * area)425 int writeToDupeFile(s_area *area) {
426    char *fileName=NULL;
427    s_dupeMemory *dupes;
428    int  rc = 0;
429 
430    if (area->dupeCheck == dcOff) return rc;
431 
432    if (config->typeDupeBase!=commonDupeBase) {
433       dupes = area->dupes;
434       fileName = createDupeFileName(area);
435    }
436    else {
437       dupes = CommonDupes;
438       xstrscat(&fileName, config->dupeHistoryDir, "hpt_base.dpa", NULLP);
439    }
440 
441    if (dupes != NULL) {
442       if (tree_count(&(dupes->avlTree)) > 0) {
443          rc = createDupeFile(area, fileName, *dupes);
444       }
445    }
446 
447    nfree(fileName);
448 
449    return rc;
450 }
451 
452 
freeDupeMemory(s_area * area)453 void freeDupeMemory(s_area *area) {
454    s_dupeMemory *dupes;
455 
456    if (area->dupeCheck == dcOff) return;
457 
458    if (config->typeDupeBase != commonDupeBase)
459       dupes = area -> dupes;
460    else
461       dupes = CommonDupes;
462 
463    if (dupes != NULL) {
464       tree_mung(&(dupes -> avlTree), deleteEntry);
465       if (config->typeDupeBase != commonDupeBase) {
466          nfree(area -> dupes);
467       }
468       else {
469          nfree(CommonDupes);
470       }
471    };
472 }
473 
474 
475 /*
476  *  find start of content in echomail's message text
477  *
478  *  requires:
479  *  - msg_text: pointer to message text
480  *
481  *  returns:
482  *  - pointer to start of content or NULL in case of any error
483  */
484 
findStartOfContent(char * msg_text)485 char *findStartOfContent(char *msg_text)
486 {
487   char               *start = NULL;     /* start of content */
488   char               *temp;             /* temporary pointer */
489   unsigned int       run = TRUE;        /* loop control flag */
490 
491   /* sanity check */
492   if (msg_text == NULL) return start;
493 
494   /* message has to start with AREA: line */
495   if (strncmp(msg_text, "AREA:", 5) == 0)
496   {
497     /* find next line not starting with <soh> */
498     while (run == TRUE)
499     {
500       /* find end of current line */
501       temp = strchr(msg_text, '\r');    /* find next CR */
502 
503       if (temp)                         /* found CR */
504       {
505         /* check for <soh> */
506         temp++;                         /* first char of new line */
507         if (*temp == 0x01)              /* is <soh> */
508         {
509           msg_text = temp;              /* skip this kludge line */
510         }
511         else                            /* not <soh> */
512         {
513           start = temp;                 /* found start of content */
514           run = FALSE;                  /* end loop */
515         }
516       }
517       else                              /* no CR found */
518       {
519         run = FALSE;                    /* end loop */
520       }
521     }
522   }
523 
524   return start;
525 }
526 
527 
528 /*
529  *  find end of content in echomail's message text
530  *
531  *  requires:
532  *  - msg_text: pointer to message text
533  *
534  *  returns:
535  *  - pointer to end of content or NULL in case of any error
536  */
537 
findEndOfContent(char * msg_text)538 char *findEndOfContent(char *msg_text)
539 {
540   char               *end = NULL;       /* end of content */
541   char               *eol;              /* end of line */
542   char               *temp;             /* temporary pointer */
543   unsigned int       run = TRUE;        /* loop control flag */
544   unsigned long      length;            /* string length */
545 
546   /* sanity check */
547   if (msg_text == NULL) return end;
548 
549   /* get end of last line */
550   length = strlen(msg_text);            /* get length of message */
551   eol = msg_text + length - 1;          /* pointer to last char */
552   length = 0;                           /* use as SEEN-BY counter */
553 
554   /* find line */
555   while (run == TRUE)
556   {
557     /* find start of line (starting at the end) */
558     temp = eol;
559     if ((*temp == '\r') && (temp > msg_text)) temp--;  /* skip CR at end */
560 
561     /* next CR is end of previous line */
562     while ((*temp != '\r') && (temp > msg_text))       /* find next CR */
563     {
564       temp--;
565     }
566 
567     if (temp == msg_text)     /* no CR found or reached start of message */
568     {
569       run = FALSE;            /* end loop */
570     }
571     else                      /* found CR */
572     {
573       temp++;                 /* first char of current line */
574 
575       /* check for non-control line */
576       if (*temp != 0x01)      /* not <soh> */
577       {
578         /* check for SEEN-BY: (special case without <soh>) */
579         if (strncmp(temp, "SEEN-BY:", 8) == 0)    /* is SEEN-BY */
580         {
581           length++;                /* increase counter */
582         }
583         else                                      /* not SEEN-BY */
584         {
585           end = eol;               /* found end of content */
586           run = FALSE;             /* end loop */
587         }
588       }
589 
590       temp--;                 /* end of previous line */
591       eol = temp;             /* update pointer for next run */
592     }
593   }
594 
595   /* check for required SEEN-BY lines */
596   if (length == 0)                 /* no SEEN-BY lines */
597   {
598     end = NULL;                    /* signal error */
599   }
600 
601   return end;
602 }
603 
604 
dupeDetection(s_area * area,const s_message msg)605 int dupeDetection(s_area *area, const s_message msg) {
606     s_dupeMemory     *Dupes = area->dupes;
607     s_textDupeEntry  *entxt;
608     s_hashDupeEntry  *enhash;
609     s_hashMDupeEntry *enhashM;
610     char             *str;
611     int nRet = 0;
612 
613     w_log(LL_FUNC,"dupe.c::dupeDetection() begin");
614 
615     if (area->dupeCheck == dcOff) return 1; /*  no dupeCheck return 1 "no dupe" */
616 
617     str = (char*)MsgGetCtrlToken((byte*)msg.text, (byte*)"MSGID:");
618 
619     if (str == NULL)
620     {   /* Kluge MSGID is not found so make it from crc of message body */
621         if (msg.text)
622         {
623             char *hbuf = NULL;     /* buffer */
624             char *start;           /* start of content */
625             char *end;             /* end of content */
626             char orig;             /* original character */
627 
628             /* isolate content from message text (no control lines) */
629             end = NULL;
630             start = findStartOfContent(msg.text);    /* find start of content */
631             if (start)                               /* found start */
632             {
633                 end = findEndOfContent(start);       /* find end of content */
634                 if (end)                             /* found end */
635                 {
636                     orig = *end;                     /* save original char */
637                     *end = 0;                        /* end string */
638                 }
639             }
640 
641             if (end == NULL)            /* just in case something went wrong */
642             {
643                 start = msg.text;       /* use complete message text */
644             }
645 
646             /* create pseudo MSGID */
647             xstrscat(&hbuf,start,msg.fromUserName,msg.datetime,msg.toUserName,msg.subjectLine,NULLP);
648             xscatprintf (&str, "MSGID: %08lx",strcrc32(hbuf, 0xFFFFFFFFL));
649             nfree(hbuf);
650 
651             if (end)                    /* un-modify message text */
652             {
653                 *end = orig;            /* restore original char */
654             }
655         }
656         else
657             return 1; /*  without msg.text - message is empty, no dupeCheck */
658     }
659     /*   testif dupeDatabase is already read */
660     if (config->typeDupeBase != commonDupeBase) {
661         if (area->dupes == NULL) {
662             Dupes = area->dupes = readDupeFile(area); /* read Dupes */
663         }
664     }
665     else {
666         if (CommonDupes == NULL) {
667             CommonDupes = readDupeFile(area); /* read Dupes */
668         }
669     }
670 
671     memset(&hashBuf,0,HASHBUFSIZE);
672     switch (config->typeDupeBase) {
673     case hashDupes:
674         enhash = safe_malloc(sizeof(s_hashDupeEntry));
675         strnzcpy(hashBuf, area->areaName,   AREANAMELEN);
676         /*
677         strnzcpy(hashBuf, msg.fromUserName, XMSG_FROM_SIZE);
678         strnzcat(hashBuf, msg.toUserName,   XMSG_TO_SIZE);
679         strnzcat(hashBuf, msg.subjectLine,  XMSG_SUBJ_SIZE);
680         */
681         strnzcat(hashBuf, str+MSGIDPOS,     3*XMSG_TO_SIZE);
682         enhash->CrcOfDupe       = strcrc32(hashBuf, 0xFFFFFFFFL);
683         enhash->TimeStampOfDupe = TimeStamp;
684         nRet = tree_add(&(Dupes->avlTree), compareEntries, (char *) enhash, deleteEntry);
685         break;
686 
687     case hashDupesWmsgid:
688         enhashM = safe_malloc(sizeof(s_hashMDupeEntry));
689         strnzcpy(hashBuf, area->areaName,   AREANAMELEN);
690         /*
691         strnzcpy(hashBuf, msg.fromUserName, XMSG_FROM_SIZE);
692         strnzcat(hashBuf, msg.toUserName,   XMSG_TO_SIZE);
693         strnzcat(hashBuf, msg.subjectLine,  XMSG_SUBJ_SIZE);
694         */
695         strnzcat(hashBuf, str+MSGIDPOS,     3*XMSG_TO_SIZE);
696         enhashM->msgid = safe_malloc(strlen(str)+1-MSGIDPOS);
697         strcpy(enhashM->msgid, str+MSGIDPOS);
698         enhashM->CrcOfDupe       = strcrc32(hashBuf, 0xFFFFFFFFL);
699         enhashM->TimeStampOfDupe = TimeStamp;
700         nRet = tree_add(&(Dupes->avlTree), compareEntries, (char *) enhashM, deleteEntry);
701         break;
702 
703     case textDupes:
704         entxt = safe_malloc(sizeof(s_textDupeEntry));
705         entxt->TimeStampOfDupe = TimeStamp;
706 
707         entxt->msgid   = safe_malloc(strlen(str)+2-MSGIDPOS);
708         strcpy(entxt->msgid, str+MSGIDPOS);
709         nRet = tree_add(&(Dupes->avlTree), compareEntries, (char *) entxt, deleteEntry);
710         break;
711 
712     case commonDupeBase:
713         enhash = safe_malloc(sizeof(s_hashDupeEntry));
714         strnzcpy(hashBuf, area->areaName,   AREANAMELEN);
715         /*
716         strnzcat(hashBuf, msg.fromUserName, XMSG_FROM_SIZE);
717         strnzcat(hashBuf, msg.toUserName,   XMSG_TO_SIZE);
718         strnzcat(hashBuf, msg.subjectLine,  XMSG_SUBJ_SIZE);
719         */
720         strnzcat(hashBuf, str+MSGIDPOS,     3*XMSG_TO_SIZE);
721         enhash->CrcOfDupe       = strcrc32(hashBuf, 0xFFFFFFFFL);
722         enhash->TimeStampOfDupe = TimeStamp;
723         nRet = tree_add(&(CommonDupes->avlTree), compareEntries, (char *) enhash, deleteEntry);
724         break;
725     }
726     nfree(str);
727     w_log(LL_FUNC,"dupe.c::dupeDetection() end nRet = %d", nRet);
728     return nRet;
729 }
730 
731