1 /*****************************************************************************
2 * HPT --- FTN NetMail/EchoMail Tosser
3 *****************************************************************************
4 * Copyright (C) 1997-1999
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 * This file is part of HPT.
16 *
17 * HPT is free software; you can redistribute it and/or modify it
18 * under the terms of the GNU General Public License as published by the
19 * Free Software Foundation; either version 2, or (at your option) any
20 * later version.
21 *
22 * HPT is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with HPT; see the file COPYING. If not, write to the Free
29 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
30 *****************************************************************************
31 * $Id$
32 */
33 #include <stdlib.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <ctype.h>
37 #include <assert.h>
38 #include <fcommon.h>
39 #include <areafix/areafix.h>
40 #include <global.h>
41 #include <seenby.h>
42 #include <huskylib/xstr.h>
43 #include <fidoconf/common.h>
44
compare(const void * first,const void * second)45 int compare(const void *first, const void *second)
46 {
47 if ( ((s_seenBy*) first)->net < ((s_seenBy*) second)->net) return -1;
48 else
49 if ( ((s_seenBy*) first)->net > ((s_seenBy*) second)->net) return 1;
50 else if ( ((s_seenBy*) first)->node < ((s_seenBy*) second)->node) return -1;
51 else if ( ((s_seenBy*) first)->node > ((s_seenBy*) second)->node) return 1;
52 return 0;
53 }
54
sortSeenBys(s_seenBy * seenBys,UINT count)55 void sortSeenBys(s_seenBy *seenBys, UINT count)
56 {
57 assert(seenBys != NULL || count == 0);
58 if(count)
59 qsort(seenBys, count, sizeof(s_seenBy), compare);
60 }
61
createControlText(s_seenBy seenBys[],UINT seenByCount,char * lineHeading)62 char *createControlText(s_seenBy seenBys[], UINT seenByCount, char *lineHeading)
63 {
64 #define size 81
65 #define addr2dSize 13
66 UINT i;
67 char *text=NULL, *line = NULL, addr2d[addr2dSize];
68
69 if (seenByCount==0) { /* return empty control line */
70 xstrcat(&text, lineHeading);
71 /* reserve one byte for \r */
72 text = (char *) safe_realloc(text, strlen(text)+2);
73 } else {
74
75 line = safe_malloc ((size_t) size);
76
77 sprintf(addr2d, "%u/%u", seenBys[0].net, seenBys[0].node);
78 text = (char *) safe_malloc((size_t) size);
79 text[0]='\0';
80 strncpy(line, lineHeading, size);
81 strncat(line, addr2d, size);
82 for (i=1; i < seenByCount; i++) {
83
84 /* fix for double seen-by's (may be after ignoreSeen) */
85 /* NOTE! fixed seen-by's hides shitty tossers! */
86 /* it is not recommended to uncomment this. */
87 /* if (config->ignoreSeenCount && */
88 /* seenBys[i-1].net == seenBys[i].net && */
89 /* seenBys[i-1].node == seenBys[i].node) continue; */
90
91 if (seenBys[i-1].net == seenBys[i].net)
92 sprintf(addr2d, " %u", seenBys[i].node);
93 else
94 sprintf(addr2d, " %u/%u", seenBys[i].net, seenBys[i].node);
95
96 if (strlen(line)+strlen(addr2d) > size-3) {
97 /* if line would be greater than 79 characters, make new line */
98 strcat(text, line);
99 strncat(text, "\r", size);
100 text = (char *) safe_realloc(text,strlen(text)+size);
101 strncpy(line, lineHeading, size);
102 /* start new line with full 2d information */
103 sprintf(addr2d, "%u/%u", seenBys[i].net, seenBys[i].node);
104 }
105 strcat(line, addr2d);
106 }
107 /* reserve only needed space + ending \r */
108 text = (char *) safe_realloc(text, strlen(text)+strlen(line)+2);
109 strcat(text,line);
110 nfree(line);
111 }
112
113 strncat(text, "\r", size);
114
115 return text;
116 }
117
createSeenByArrayFromMsg(s_area * area,s_message * msg,s_seenBy ** seenBys,UINT * seenByCount)118 void createSeenByArrayFromMsg(s_area *area, s_message *msg, s_seenBy **seenBys, UINT *seenByCount)
119 {
120 char *seenByText=NULL, *start = NULL, *token = NULL;
121 unsigned long temp;
122 char *endptr = NULL;
123 UINT seenByAlloced;
124
125 unused(area);
126
127 *seenByCount = seenByAlloced = 0;
128
129 start = strrstr(msg->text, " * Origin:"); /* jump over Origin */
130 if (start == NULL) start = msg->text;
131
132 /* find beginning of seen-by lines */
133 do {
134 start = strstr(start, "SEEN-BY:");
135 if (start == NULL) return;
136 start += 8; /* jump over SEEN-BY: */
137
138 while (*start == ' ') start++; /* find first word after SEEN-BY: */
139 } while (!isdigit(*start));
140
141 /* now that we have the start of the SEEN-BY's we can tokenize the lines and read them in */
142 xstrcat(&seenByText, start);
143
144 token = strtok(seenByText, " \r\t\376");
145 for (; token != NULL; token = strtok(NULL, " \r\t\376")) {
146 if (isdigit(*token)) {
147 /* parse token */
148 temp = strtoul(token, &endptr, 10);
149 if (*endptr==':') {
150 token = endptr+1;
151 temp = strtoul(token, &endptr, 10);
152 }
153 if (*endptr && *endptr != '/')
154 continue;
155
156 /* get new memory */
157 if ((*seenByCount)++ >= seenByAlloced)
158 (*seenBys) = (s_seenBy*) safe_realloc(*seenBys, sizeof(s_seenBy) * (seenByAlloced+=32));
159
160 if ((*endptr) == '\0') {
161 /* only node aka */
162 (*seenBys)[*seenByCount-1].node = (UINT16) temp;
163 /* use net aka of last seenBy */
164 if(*seenByCount >= 2)
165 (*seenBys)[*seenByCount-1].net = (*seenBys)[*seenByCount-2].net;
166 else
167 { /* Shouldn't really happen. The best way out is unclear. */
168 /* I propose to drop incorrect seen-by's, as possible dupes seem to be lesser evil
169 compared to possible loss of mail if choose to propagate mail with buggy control
170 lines --Elfy 2010-03-18 */
171 w_log(LL_ALERT, "Buggy SEEN-BY line encountered. Invalid node was removed from the line!"); /* FIXME: print msgid to pinpoint problem? */
172 --*seenByCount;
173 }
174 } else {
175 /* net and node aka */
176 (*seenBys)[*seenByCount-1].net = (UINT16) temp;
177 /* eat up '/' */
178 endptr++;
179 (*seenBys)[*seenByCount-1].node = (UINT16) atol(endptr);
180 }
181 } else if (strcmp(token,"SEEN-BY:")!=0) break; /* not digit and not SEEN-BY */
182
183 } /* end while */
184
185 if (*seenByCount != seenByAlloced)
186 {
187 if(*seenByCount > 0)
188 (*seenBys) = (s_seenBy*) safe_realloc(*seenBys, sizeof(s_seenBy) * (*seenByCount));
189 else
190 {
191 nfree(*seenBys);
192 seenByAlloced = 0;
193 }
194 }
195 /* test output for reading of seenBys... */
196 #ifdef DEBUG_HPT
197 for (i=0; i < *seenByCount; i++) printf("%u/%u ", (*seenBys)[i].net, (*seenBys)[i].node);
198 #endif
199 /* exit(2); */
200
201 nfree(seenByText);
202 }
203
createPathArrayFromMsg(s_message * msg,s_seenBy ** seenBys,UINT * seenByCount)204 void createPathArrayFromMsg(s_message *msg, s_seenBy **seenBys, UINT *seenByCount)
205 {
206
207 /* DON'T GET MESSED UP WITH THE VARIABLES NAMED SEENBY... */
208 /* THIS FUNCTION READS PATH!!! */
209
210 char *seenByText=NULL, *start = NULL, *token = NULL;
211 char *endptr = NULL;
212 unsigned long temp;
213 UINT seenByAlloced;
214 #ifdef DEBUG_HPT
215 int i;
216 #endif
217
218 *seenByCount = seenByAlloced = 0;
219
220 start = strrstr(msg->text, " * Origin:"); /* jump over Origin */
221 if (start == NULL)
222 start = msg->text;
223
224 /* find beginning of path lines */
225 do
226 {
227 start = strstr(start, "\001PATH:");
228 if (start == NULL)
229 return;
230 for (endptr = strchr(start, '\r'); endptr; endptr = strchr(endptr, '\r'))
231 {
232 while (*endptr == '\r' || *endptr == '\n')
233 endptr++;
234 if (strncmp(endptr, "\001PATH:", 6))
235 break; /* not path line */
236 }
237 if (endptr && strstr(endptr, "\001PATH:"))
238 {
239 start = endptr;
240 continue; /* only last path lines are valid */
241 }
242 start += 7; /* jump over PATH: */
243
244 while (*start == ' ')
245 start++; /* find first word after PATH: */
246 } while (!isdigit(*start));
247
248 /* now that we have the start of the PATH' so we can tokenize the lines and read them in */
249 xstrcat(&seenByText, start);
250
251 token = strtok(seenByText, " \r\t\376");
252 for (; token != NULL; token = strtok(NULL, " \r\t\376"))
253 {
254 if (isdigit(*token))
255 {
256 /* parse token */
257 temp = strtoul(token, &endptr, 10);
258 if (*endptr==':')
259 {
260 token = endptr+1;
261 temp = strtoul(token, &endptr, 10);
262 }
263 if (*endptr && *endptr != '/')
264 continue;
265
266 /* get new memory */
267 if ((*seenByCount)++ >= seenByAlloced)
268 (*seenBys) = (s_seenBy*) safe_realloc(*seenBys, sizeof(s_seenBy) * (seenByAlloced+=32));
269
270 if ((*endptr) == '\0')
271 {
272 /* only node aka */
273 (*seenBys)[*seenByCount-1].node = (UINT16) temp;
274 /* use net aka of last seenBy */
275 if(*seenByCount >= 2)
276 {
277 (*seenBys)[*seenByCount-1].net = (*seenBys)[*seenByCount-2].net;
278 }
279 else
280 {
281 w_log(LL_ALERT, "Buggy PATH line encountered. Invalid node was removed from the line!");
282 --*seenByCount;
283 }
284 }
285 else
286 {
287 /* net and node aka */
288 (*seenBys)[*seenByCount-1].net = (UINT16) temp;
289 /* eat up '/' */
290 endptr++;
291 (*seenBys)[*seenByCount-1].node = (UINT16) atol(endptr);
292 }
293 }
294 else if (strcmp(token, "\001PATH:")!=0)
295 break; /* not digit and not PATH */
296 }
297
298 if (*seenByCount != seenByAlloced)
299 (*seenBys) = (s_seenBy*) safe_realloc(*seenBys, sizeof(s_seenBy) * (*seenByCount));
300
301 /* test output for reading of paths... */
302 #ifdef DEBUG_HPT
303 for (i=0; i < *seenByCount; i++)
304 printf("%u/%u ", (*seenBys)[i].net, (*seenBys)[i].node);
305 #endif
306 /* exit(2); */
307
308 nfree(seenByText);
309 }
310
311 /**
312 * This function returns 0 if the link is not in seenBy else it returns 1.
313 */
314
checkLink(s_seenBy * seenBys,UINT seenByCount,s_link * link,hs_addr pktOrigAddr,s_area * area)315 int checkLink(s_seenBy *seenBys, UINT seenByCount, s_link *link,
316 hs_addr pktOrigAddr, s_area *area)
317 {
318 UINT i,j;
319
320 /* the link where we got the mail from */
321 if (addrComp(pktOrigAddr, link->hisAka) == 0) return 1;
322
323 if (seenBys==NULL) return 0;
324
325 /* a point always gets the mail */
326 /* if (link->hisAka.point != 0) return 0; */
327
328 /* send the mail to links within our node-system */
329 if ((link->hisAka.zone == area->useAka->zone) &&
330 (link->hisAka.net == area->useAka->net) &&
331 (link->hisAka.node == area->useAka->node))
332 return 0;
333
334 for (i=0; i < seenByCount; i++) {
335 if ((link->hisAka.net==seenBys[i].net) &&
336 (link->hisAka.node==seenBys[i].node)) {
337
338 for (j=0; j < config->ignoreSeenCount; j++) {
339 if (config->ignoreSeen[j].net == seenBys[i].net &&
340 config->ignoreSeen[j].node == seenBys[i].node) {
341 link->sb = 1; /* fix for double seen-bys */
342 return 0;
343 }
344 }
345 for (j=0; j < area->sbignCount; j++) {
346 if (area->sbign[j].net == seenBys[i].net &&
347 area->sbign[j].node == seenBys[i].node) {
348 link->sb = 1; /* fix for double seen-bys */
349 return 0;
350 }
351 }
352
353 return 1;
354 }
355 }
356 return 0;
357 }
358
359 /*
360 This function puts all the links of the echoarea in the newLink
361 array who does not have got the mail, zoneLinks - the links who
362 receive msg with stripped seen-by's.
363 */
364
createNewLinkArray(s_seenBy * seenBys,UINT seenByCount,s_area * echo,s_arealink *** newLinks,s_arealink *** zoneLinks,s_arealink *** otherLinks,hs_addr pktOrigAddr)365 void createNewLinkArray(s_seenBy *seenBys, UINT seenByCount,
366 s_area *echo,
367 s_arealink ***newLinks,
368 s_arealink ***zoneLinks,
369 s_arealink ***otherLinks,
370 hs_addr pktOrigAddr)
371 {
372 UINT i, lFound = 0, zFound = 0, oFound = 0;
373
374 *newLinks = (s_arealink **)safe_calloc(echo->downlinkCount,sizeof(s_arealink*));
375 *zoneLinks = (s_arealink **)safe_calloc(echo->downlinkCount,sizeof(s_arealink*));
376 *otherLinks =(s_arealink **)safe_calloc(echo->downlinkCount,sizeof(s_arealink*));
377
378 for (i=0; i < echo->downlinkCount; i++) {
379 /* is the link in SEEN-BYs? */
380 if ( checkLink(seenBys, seenByCount, echo->downlinks[i]->link,
381 pktOrigAddr, echo)!=0) continue;
382 /* link with "export off" */
383 if (echo->downlinks[i]->aexport == 0) continue;
384
385 if (pktOrigAddr.zone==echo->downlinks[i]->link->hisAka.zone) {
386 /* links with same zone */
387 if(echo->downlinks[i]->link->reducedSeenBy)
388 {
389 (*otherLinks)[oFound++] = echo->downlinks[i];
390 }
391 else
392 {
393 (*newLinks)[lFound++] = echo->downlinks[i];
394 }
395 } else {
396 /* links in different zones */
397 (*zoneLinks)[zFound++] = echo->downlinks[i];
398 }
399 }
400 if(lFound == 0)
401 nfree(*newLinks);
402 if(zFound == 0)
403 nfree(*zoneLinks);
404 if(oFound == 0)
405 nfree(*otherLinks);
406 }
407
408
409 /*
410 Create a new SEEN-BY array from another one for AKAs found in an address list.
411 */
412
createFilteredSeenByArray(s_seenBy * seenBys,UINT seenByCount,s_seenBy ** newSeenBys,UINT * newSeenByCount,ps_addr addr,unsigned int addrCount)413 void createFilteredSeenByArray(s_seenBy *seenBys, UINT seenByCount,
414 s_seenBy **newSeenBys, UINT *newSeenByCount,
415 ps_addr addr, unsigned int addrCount)
416 {
417 unsigned int i, j;
418
419 /* sanity checks */
420 if ((newSeenBys == NULL) || (newSeenByCount == NULL)) return;
421 if ((seenByCount > 0) && (seenBys == NULL)) return;
422 if ((addrCount > 0) && (addr == NULL)) return;
423
424 *newSeenByCount = 0;
425
426 /* get memory for array (required at maximum) */
427 (*newSeenBys) = (s_seenBy*)safe_calloc(addrCount, sizeof(s_seenBy));
428
429 /* search for matches */
430 for (i = 0; i < addrCount; i++) /* address array */
431 {
432 for (j = 0; j < seenByCount; j++) /* SEEN-BY array */
433 {
434 if (((UINT16)addr[i].net == seenBys[j].net) &&
435 ((UINT16)addr[i].node == seenBys[j].node))
436 {
437 /* copy this one to new array */
438 (*newSeenBys)[*newSeenByCount].net = (UINT16)addr[i].net;
439 (*newSeenBys)[*newSeenByCount].node = (UINT16)addr[i].node;
440 (*newSeenByCount)++;
441 }
442 }
443 }
444 }
445
446
447 /*
448 strip specific AKAs (address array) from SEEN-BY array
449 */
450
stripSeenByArray(s_seenBy ** seenBys,UINT * seenByCount,ps_addr addr,unsigned int addrCount)451 void stripSeenByArray(s_seenBy **seenBys, UINT *seenByCount,
452 ps_addr addr, unsigned int addrCount)
453 {
454 unsigned int i, j, k;
455 unsigned int counter;
456
457 /* sanity check */
458 if ((seenBys == NULL) || (seenByCount == NULL)) return;
459
460 counter = *seenByCount; /* local variable to speed up access */
461
462 /* search for matches */
463 for (i = 0; i < addrCount; i++) /* address array */
464 {
465 for (j = 0; j < counter; j++) /* SEEN-BY array */
466 {
467 if (((UINT16)addr[i].net == (*seenBys)[j].net) &&
468 ((UINT16)addr[i].node == (*seenBys)[j].node))
469 {
470 /* remove this AKA by moving remaining SEEN-BYs one up */
471 counter--;
472
473 for (k = j; k < counter; k++)
474 {
475 (*seenBys)[k].net = (*seenBys)[k + 1].net;
476 (*seenBys)[k].node = (*seenBys)[k + 1].node;
477 }
478 }
479 }
480 }
481
482 *seenByCount = counter; /* update counter */
483 }
484