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