linbpq/MailRouting.c

2100 lines
50 KiB
C
Raw Blame History

/*
Copyright 2001-2018 John Wiseman G8BPQ
This file is part of LinBPQ/BPQ32.
LinBPQ/BPQ32 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 3 of the License, or
(at your option) any later version.
LinBPQ/BPQ32 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 LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
*/
// Mail and Chat Server for BPQ32 Packet Switch
//
// Message Routing Module
// This code decides where to send a message.
// Private messages are routed by TO and AT if possible, if not they follow the Bull Rules
// Bulls are routed on HA where possible
// Bulls should not be distributed outside their designated area.
// Use 4 char continent codes if this is set
int FOURCHARCONT = 0;
#include "bpqmail.h"
char WW[] = "WW";
char * MyElements[20] = {WW}; // My HA in element format
char MyRouteElements[100];
int MyElementCount;
BOOL ReaddressLocal = 0;
BOOL ReaddressReceived = 0;
BOOL WarnNoRoute = TRUE;
BOOL SendPtoMultiple = FALSE;
BOOL Localtime = FALSE; // Use Local Time for Timebands and forward connect scripts
struct ALIAS * CheckForNTSAlias(struct MsgInfo * Msg, char * FirstDestElement);
struct UserInfo * FindAMPR();
struct UserInfo * FindBBS(char * Name);
struct Continent
{
char FourCharCode[5];
char TwoCharCode[5];
};
struct Country
{
char Country[5];
char Continent4[5];
char Continent2[3];
};
struct Continent Continents[] =
{
"EURO", "EU", // Europe
"MEDR", "EU", // Mediterranean
"ASIA", "AS", // The Orient
"INDI", "AS", // Indian Ocean including the Indian subcontinent
"MDLE", "AS", // Middle East
"SEAS", "AS", // South-East Asia
"NOAM", "NA", // North America (Canada, USA, Mexico)
"CEAM", "NA", // Central America
"CARB", "NA", // Caribbean
"SOAM", "SA", // South America
"AUNZ", "OC", // Australia/New Zealand
"EPAC", "OC", // Eastern Pacific
"NPAC", "OC", // Northern Pacific
"SPAC", "OC", // Southern Pacific
"WPAC", "OC", // Western Pacific
"NAFR", "AF", // Northern Africa
"CAFR", "AF", // Central Africa
"SAFR", "AF", // Southern Africa
"ANTR", "OC", // Antarctica
"MARS", "MARS", // Special for MARS network
};
struct Country Countries[] =
{
"AFG", "ASIA", "AS", // Afghanistan
"ALA", "EURO", "EU", // <20>land Islands
"ALB", "EURO", "EU", // Albania
"DZA", "NAFR", "AF", // Algeria
"ASM", "ASIA", "AS", // American Samoa
"AND", "EURO", "EU", // Andorra
"AGO", "CAFR", "AF", // Angola
"AIA", "CARB", "NA", // Anguilla
"ATG", "CARB", "NA", // Antigua and Barbuda
"ARG", "SOAM", "SA", // Argentina
"ARM", "ASIA", "AS", // Armenia
"ABW", "CARB", "NA", // Aruba
"AUS", "AUNZ", "OC", // Australia
"AUT", "EURO", "EU", // Austria
"AZE", "ASIA", "AS", // Azerbaijan
"BHS", "CARB", "NA", // Bahamas
"BHR", "MDLE", "AS", // Bahrain
"BGD", "INDE", "AS", // Bangladesh
"BRB", "CARB", "NA", // Barbados
"BLR", "EURO", "EU", // Belarus
"BEL", "EURO", "EU", // Belgium
"BLZ", "CEAM", "NA", // Belize
"BEN", "CAFR", "AF", // Benin
"BMU", "CARB", "NA", // Bermuda
"BTN", "ASIA", "AS", // Bhutan
"BOL", "SOAM", "SA", // Bolivia (Plurinational State of)
"BIH", "EURO", "EU", // Bosnia and Herzegovina
"BWA", "SAFR", "AF", // Botswana
"BRA", "SOAM", "SA", // Brazil
"VGB", "CARB", "NA", // British Virgin Islands
"BRN", "ASIA", "AS", // Brunei Darussalam
"BGR", "EURO", "EU", // Bulgaria
"BFA", "CAFR", "AF", // Burkina Faso
"BDI", "CAFR", "AF", // Burundi
"KHM", "ASIA", "AS", // Cambodia
"CMR", "CAFR", "AF", // Cameroon
"CAN", "NOAM", "NA", // Canada
"CPV", "NAFR", "AF", // Cape Verde
"CYM", "CARB", "NA", // Cayman Islands
"CAF", "CAFR", "AF", // Central African Republic
"TCD", "CAFR", "AF", // Chad
"CHL", "SOAM", "SA", // Chile
"CHN", "ASIA", "AS", // China
"HKG", "ASIA", "AS", // Hong Kong Special Administrative Region of China
"MAC", "ASIA", "AS", // Macao Special Administrative Region of China
"COL", "ASIA", "SA", // Colombia
"COM", "SAFR", "AF", // Comoros
"COG", "CAFR", "AF", // Congo
"COK", "SPAC", "OC", // Cook Islands
"CRI", "CEAM", "NA", // Costa Rica
"CIV", "CAFR", "AF", // C<>te d'Ivoire
"HRV", "EURO", "EU", // Croatia
"CUB", "CARB", "NA", // Cuba
"CYP", "EURO", "EU", // Cyprus
"CZE", "EURO", "EU", // Czech Republic
"PRK", "ASIA", "AS", // Democratic People's Republic of Korea
"COD", "CAFR", "AF", // Democratic Republic of the Congo
"DNK", "EURO", "EU", // Denmark
"DJI", "NAFR", "AF", // Djibouti
"DMA", "CARB", "NA", // Dominica
"DOM", "CARB", "NA", // Dominican Republic
"ECU", "SOAM", "SA", // Ecuador
"EGY", "MDLE", "AF", // Egypt
"SLV", "CEAM", "NA", // El Salvador
"GNQ", "CAFR", "AF", // Equatorial Guinea
"ERI", "NAFR", "AF", // Eritrea
"EST", "EURO", "EU", // Estonia
"ETH", "NAFR", "AF", // Ethiopia
"FRO", "EURO", "EU", // Faeroe Islands
"FLK", "SOAM", "SA", // Falkland Islands (Malvinas)
"FJI", "SPAC", "OC", // Fiji
"FIN", "EURO", "EU", // Finland
"FRA", "EURO", "EU", // France
"GUF", "SOAM", "SA", // French Guiana
"PYF", "SPAC", "OC", // French Polynesia
"GAB", "CAFR", "AF", // Gabon
"GMB", "CAFR", "AF", // Gambia
"GEO", "ASIA", "AS", // Georgia
"DEU", "EURO", "EU", // Germany
"GHA", "CAFR", "AF", // Ghana
"GIB", "EURO", "EU", // Gibraltar
"GRC", "EURO", "EU", // Greece
"GRL", "EURO", "EU", // Greenland
"GRD", "CARB", "NA", // Grenada
"GLP", "CARB", "NA", // Guadeloupe
"GUM", "SPAC", "OC", // Guam
"GTM", "CEAM", "NA", // Guatemala
"GGY", "EURO", "EU", // Guernsey
"GIN", "CAFR", "AF", // Guinea
"GNB", "CAFR", "AF", // Guinea-Bissau
"GUY", "SOAM", "SA", // Guyana
"HTI", "CARB", "NA", // Haiti
"VAT", "EURO", "EU", // Holy See
"HND", "CEAM", "NA", // Honduras
"HUN", "EURO", "EU", // Hungary
"ISL", "EURO", "EU", // Iceland
"IND", "INDI", "AS", // India
"IDN", "ASIA", "AS", // Indonesia
"IRN", "MDLE", "AS", // Iran (Islamic Republic of)
"IRQ", "MDLE", "AS", // Iraq
"IRL", "EURO", "EU", // Ireland
"IMN", "EURO", "EU", // Isle of Man
"ISR", "MDLE", "AS", // Israel
"ITA", "EURO", "EU", // Italy
"JAM", "CEAM", "NA", // Jamaica
"JPN", "ASIA", "AS", // Japan
"JEY", "EURO", "EU", // Jersey
"JOR", "MDLE", "AS", // Jordan
"KAZ", "ASIA", "AS", // Kazakhstan
"KEN", "CAFR", "AF", // Kenya
"KIR", "EPAC", "OC", // Kiribati
"KWT", "MDLE", "AS", // Kuwait
"KGZ", "ASIA", "AS", // Kyrgyzstan
"LAO", "ASIA", "AS", // Lao People's Democratic Republic
"LVA", "EURO", "EU", // Latvia
"LBN", "MDLE", "AS", // Lebanon
"LSO", "SAFR", "AF", // Lesotho
"LBR", "CAFR", "AF", // Liberia
"LBY", "MDLE", "AS", // Libyan Arab Jamahiriya
"LIE", "EURO", "EU", // Liechtenstein
"LTU", "EURO", "EU", // Lithuania
"LUX", "EURO", "EU", // Luxembourg
"MDG", "SAFR", "AF", // Madagascar
"MWI", "SAFR", "AF", // Malawi
"MYS", "ASIA", "AS", // Malaysia
"MDV", "INDI", "AS", // Maldives
"MLI", "CAFR", "AF", // Mali
"MLT", "EURO", "EU", // Malta
"MHL", "WPAC", "OC", // Marshall Islands
"MTQ", "CARB", "NA", // Martinique
"MRT", "NAFR", "AF", // Mauritania
"MUS", "SAFR", "AF", // Mauritius
"MYT", "SAFR", "AF", // Mayotte
"MEX", "NOAM", "NA", // Mexico
"FSM", "WPAC", "OC", // Micronesia (Federated States of)
"MCO", "EURO", "EU", // Monaco
"MNG", "ASIA", "AS", // Mongolia
"MNE", "EURO", "EU", // Montenegro
"MSR", "CARB", "NA", // Montserrat
"MAR", "NAFR", "AF", // Morocco
"MOZ", "SAFR", "AF", // Mozambique
"MMR", "ASIA", "AS", // Myanmar
"NAM", "SAFR", "AF", // Namibia
"NRU", "WPAC", "OC", // Nauru
"NPL", "ASIA", "AS", // Nepal
"NLD", "EURO", "EU", // Netherlands
"ANT", "CARB", "NA", // Netherlands Antilles
"NCL", "SPAC", "OC", // New Caledonia
"NZL", "AUNZ", "OC", // New Zealand
"NIC", "CEAM", "SA", // Nicaragua
"NER", "NAFR", "AF", // Niger
"NGA", "CAFR", "AF", // Nigeria
"NIU", "SPAC", "OC", // Niue
"NFK", "SPAC", "OC", // Norfolk Island
"MNP", "WPAC", "OC", // Northern Mariana Islands
"NOR", "EURO", "EU", // Norway
"PSE", "MDLE", "AS", // Occupied Palestinian Territory
"OMN", "MDLE", "AS", // Oman
"PAK", "INDI", "AS", // Pakistan
"PLW", "SPAC", "OC", // Palau
"PAN", "CEAM", "SA", // Panama
"PNG", "SPAC", "OC", // Papua New Guinea
"PRY", "SOAM", "SA", // Paraguay
"PER", "SOAM", "SA", // Peru
"PHL", "ASIA", "AS", // Philippines
"PCN", "SPAC", "OC", // Pitcairn
"POL", "EURO", "EU", // Poland
"PRT", "EURO", "EU", // Portugal
"PRI", "CARB", "NA", // Puerto Rico
"QAT", "MDLE", "AS", // Qatar
"KOR", "ASIA", "AS", // Republic of Korea
"MDA", "EURO", "EU", // Republic of Moldova
"REU", "SAFR", "AF", // R<>union
"ROU", "EURO", "EU", // Romania
"RUS", "ASIA", "AS", // Russian Federation
"RWA", "CAFR", "AF", // Rwanda
"BLM", "CARB", "NA", // Saint-Barth<74>lemy
"SHN", "SOAM", "SA", // Saint Helena
"KNA", "CARB", "NA", // Saint Kitts and Nevis
"LCA", "CARB", "NA", // Saint Lucia
"MAF", "CARB", "NA", // Saint-Martin (French part)
"SPM", "NOAM", "NA", // Saint Pierre and Miquelon
"VCT", "CARB", "NA", // Saint Vincent and the Grenadines
"WSM", "SPAC", "OC", // Samoa
"SMR", "EURO", "EU", // San Marino
"STP", "CAFR", "AF", // Sao Tome and Principe
"SAU", "MDLE", "AS", // Saudi Arabia
"SEN", "CAFR", "AF", // Senegal
"SRB", "EURO", "EU", // Serbia
"SYC", "SAFR", "AF", // Seychelles
"SLE", "NAFR", "AF", // Sierra Leone
"SGP", "ASIA", "AS", // Singapore
"SVK", "EURO", "EU", // Slovakia
"SVN", "EURO", "EU", // Slovenia
"SLB", "SPAC", "OC", // Solomon Islands
"SOM", "NAFR", "AF", // Somalia
"ZAF", "SAFR", "AF", // South Africa
"ESP", "EURO", "EU", // Spain
"LKA", "INDE", "AS", // Sri Lanka
"SDN", "NAFR", "AF", // Sudan
"SUR", "SOAM", "SA", // Suriname
"SJM", "EURO", "EU", // Svalbard and Jan Mayen Islands
"SWZ", "SAFR", "AF", // Swaziland
"SWE", "EURO", "EU", // Sweden
"CHE", "EURO", "EU", // Switzerland
"SYR", "MDLE", "AS", // Syrian Arab Republic
"TJK", "ASIA", "AS", // Tajikistan
"THA", "ASIA", "AS", // Thailand
"MKD", "EURO", "EU", // The former Yugoslav Republic of Macedonia
"TLS", "ASIA", "AS", // Timor-Leste
"TGO", "CAFR", "AF", // Togo
"TKL", "AUNZ", "OC", // Tokelau
"TON", "SPAC", "OC", // Tonga
"TTO", "CARB", "NA", // Trinidad and Tobago
"TUN", "NAFR", "AF", // Tunisia
"TUR", "EURO", "EU", // Turkey
"TKM", "ASIA", "AS", // Turkmenistan
"TCA", "CARB", "NA", // Turks and Caicos Islands
"TUV", "SPAC", "OC", // Tuvalu
"UGA", "SAFR", "AF", // Uganda
"UKR", "EURO", "EU", // Ukraine
"ARE", "MDLE", "AS", // United Arab Emirates
"GBR", "EURO", "EU", // United Kingdom of Great Britain and Northern Ireland
"TZA", "SAFR", "AF", // United Republic of Tanzania
"USA", "NOAM", "NA", // United States of America
"VIR", "CARB", "NA", // United States Virgin Islands
"URY", "SOAM", "SA", // Uruguay
"UZB", "ASIA", "AS", // Uzbekistan
"VUT", "SPAC", "OC", // Vanuatu
"VEN", "SOAM", "SA", // Venezuela (Bolivarian Republic of)
"VNM", "ASIA", "AS", // Viet Nam
"WLF", "SPAC", "OC", // Wallis and Futuna Islands
"ESH", "CAFR", "AF", // Western Sahara
"YEM", "NAFR", "AF", // Yemen
"ZMB", "SAFR", "AF", // Zambia
"ZWE", "SAFR", "AF" // Zimbabwe
};
char ** AliasText;
struct ALIAS ** Aliases;
struct ALIAS ** NTSAliases = NULL;
/*struct ALIAS Aliases[] =
{
"AMSAT", "WW",
"USBBS", "USA",
"ALLUS", "USA"};
*/
int NumberofContinents = sizeof(Continents)/sizeof(Continents[1]);
int NumberofCountries = sizeof(Countries)/sizeof(Countries[1]);
struct Continent * FindContinent(char * Name)
{
int i;
struct Continent * Cont;
for(i=0; i< NumberofContinents; i++)
{
Cont = &Continents[i];
if ((_stricmp(Name, Cont->FourCharCode) == 0) || (_stricmp(Name, Cont->TwoCharCode) == 0))
return Cont;
}
return NULL;
}
struct Country * FindCountry(char * Name)
{
int i;
struct Country * Cont;
for(i=0; i< NumberofCountries; i++)
{
Cont = &Countries[i];
if (_stricmp(Name, Cont->Country) == 0)
return Cont;
}
return NULL;
}
struct ALIAS * FindAlias(char * Name)
{
struct ALIAS ** Alias;
Alias = Aliases;
while(Alias[0])
{
if (_stricmp(Name, Alias[0]->Dest) == 0)
return Alias[0];
Alias++;
}
return NULL;
}
VOID SetupMyHA()
{
int Elements = 1; // Implied WW on front
char * ptr2;
struct Continent * Continent;
strcpy(MyRouteElements, HRoute);
// Split it up
ptr2 = MyRouteElements + strlen(MyRouteElements) - 1;
if (HRoute[0])
{
do
{
while ((*ptr2 != '.') && (ptr2 > MyRouteElements))
ptr2 --;
if (ptr2 == MyRouteElements)
{
// End
MyElements[Elements++] = _strdup(ptr2);
break;
}
MyElements[Elements++] = _strdup(ptr2+1);
*ptr2 = 0;
} while(Elements < 19); // Just in case!
}
MyElements[Elements++] = _strdup(BBSName);
MyElementCount = Elements;
if (MyElements[1])
{
if (FOURCHARCONT == 0)
{
if (strlen(MyElements[1]) == 4)
{
// Convert to 2 char Continent;
Continent = FindContinent(MyElements[1]);
if (Continent)
{
free(MyElements[1]);
MyElements[1] = _strdup(Continent->TwoCharCode);
}
}
}
else
{
if (strlen(MyElements[1]) == 2)
{
// Convert to 4 char Continent;
Continent = FindContinent(MyElements[1]);
if (Continent)
{
free(MyElements[1]);
MyElements[1] = _strdup(Continent->FourCharCode);
}
}
}
}
}
VOID SetupNTSAliases(char * FN)
{
FILE *in;
char Buffer[2048];
char *buf = Buffer;
int Count = 0;
char seps[] = " ,:/\t";
char * Dest, * Alias, * Context;
NTSAliases = zalloc(sizeof(struct ALIAS));
in = fopen(FN, "r");
if (in)
{
while(fgets(buf, 128, in))
{
strlop(buf, '\n');
strlop(buf, '\r'); // in case Windows Format
Dest = _strdup(buf); // strtok changes it
Dest = strtok_s(Dest, seps, &Context);
if (Dest == NULL)
continue;
Alias = strtok_s(NULL, seps, &Context);
if (Alias == NULL)
continue;
if (strlen(Dest) < 3 && (strchr(Dest, '*') == 0))
continue;
NTSAliases = realloc(NTSAliases, (Count+2)* sizeof(struct ALIAS));
NTSAliases[Count] = zalloc(sizeof(struct ALIAS));
NTSAliases[Count]->Dest = Dest;
NTSAliases[Count]->Alias = Alias;
Count++;
}
NTSAliases[Count] = NULL;
fclose(in);
}
}
VOID SetupFwdAliases()
{
char ** Text = AliasText;
char * Dest, * Alias;
int Count = 0;
char seps[] = " ,:/";
Aliases = zalloc(sizeof(struct ALIAS));
if (Text)
{
while(Text[0])
{
Aliases = realloc(Aliases, (Count+2)* sizeof(struct ALIAS));
Aliases[Count] = zalloc(sizeof(struct ALIAS));
Dest = _strdup(Text[0]); // strtok changes it
Dest = strtok_s(Dest, seps, &Alias);
Aliases[Count]->Dest = Dest;
Aliases[Count]->Alias = Alias;
Count++;
Text++;
}
Aliases[Count] = NULL;
}
}
VOID SetupHAElements(struct BBSForwardingInfo * ForwardingInfo)
{
char * HText = ForwardingInfo->BBSHA;
char * SaveHText, * ptr2;
struct Continent * Continent;
int Elements = 1;
ForwardingInfo->BBSHAElements = zalloc(8); // always NULL entry on end even if no values
SaveHText = _strdup(HText);
ptr2 = SaveHText + strlen(SaveHText) -1;
ForwardingInfo->BBSHAElements[0] = _strdup(WW);
do
{
ForwardingInfo->BBSHAElements = realloc(ForwardingInfo->BBSHAElements, (Elements+2) * sizeof(void *));
while ((*ptr2 != '.') && (ptr2 > SaveHText))
{
ptr2 --;
}
if (ptr2 == SaveHText)
{
// End
ForwardingInfo->BBSHAElements[Elements++] = _strdup(ptr2);
break;
}
ForwardingInfo->BBSHAElements[Elements++] = _strdup(ptr2+1);
*ptr2 = 0;
} while(TRUE);
ForwardingInfo->BBSHAElements[Elements++] = NULL;
if (ForwardingInfo->BBSHAElements[1])
{
if (FOURCHARCONT == 0)
{
if (strlen(ForwardingInfo->BBSHAElements[1]) == 4)
{
// Convert to 2 char Continent;
Continent = FindContinent(ForwardingInfo->BBSHAElements[1]);
if (Continent)
{
free(ForwardingInfo->BBSHAElements[1]);
ForwardingInfo->BBSHAElements[1] = _strdup(Continent->TwoCharCode);
}
}
}
else
{
if (strlen(ForwardingInfo->BBSHAElements[1]) == 2)
{
// Convert to 4 char Continent;
Continent = FindContinent(ForwardingInfo->BBSHAElements[1]);
if (Continent)
{
free(ForwardingInfo->BBSHAElements[1]);
ForwardingInfo->BBSHAElements[1] = _strdup(Continent->FourCharCode);
}
}
}
}
free(SaveHText);
}
VOID SetupHAddreses(struct BBSForwardingInfo * ForwardingInfo)
{
int Count=0;
char ** HText = ForwardingInfo->Haddresses;
char * SaveHText, * ptr2;
// char * TopElement;
char * Num;
struct Continent * Continent;
ForwardingInfo->HADDRS = zalloc(sizeof(void *)); // always NULL entry on end even if no values
ForwardingInfo->HADDROffet = zalloc(sizeof(void *)); // always NULL entry on end even if no values
while(HText[0])
{
int Elements = 1;
ForwardingInfo->HADDRS = realloc(ForwardingInfo->HADDRS, (Count+2) * sizeof(void *));
ForwardingInfo->HADDROffet = realloc(ForwardingInfo->HADDROffet, (Count+2) * sizeof(void *));
ForwardingInfo->HADDRS[Count] = zalloc(8); // Always at lesat WWW and NULL
SaveHText = _strdup(HText[0]);
Num = strlop(SaveHText, ',');
ptr2 = SaveHText + strlen(SaveHText) -1;
ForwardingInfo->HADDRS[Count][0] = _strdup(WW);
if (strcmp(HText[0], "WW") != 0)
{
do
{
ForwardingInfo->HADDRS[Count] = realloc(ForwardingInfo->HADDRS[Count], (Elements+2) * sizeof(void *));
while ((*ptr2 != '.') && (ptr2 > SaveHText))
{
ptr2 --;
}
if (ptr2 == SaveHText)
{
// End
ForwardingInfo->HADDRS[Count][Elements++] = _strdup(ptr2);
break;
}
ForwardingInfo->HADDRS[Count][Elements++] = _strdup(ptr2+1);
*ptr2 = 0;
} while(TRUE);
}
ForwardingInfo->HADDRS[Count][Elements++] = NULL;
// If the route is not a complete HR (ie starting with a continent)
// Add elemets from BBS HA to complete it.
// (How do we know how many??
// ?? Still ont sure about this ??
// What i was trying to do was end up with a full HR, but knowing how many elements to use.
// Far simpler to config it, but can users cope??
// Will config for testing. HA, N
/*
TopElement=ForwardingInfo->HADDRS[Count][0];
if (strcmp(TopElement, MyElements[0]) == 0)
goto FullHR;
if (FindContinent(TopElement))
goto FullHR;
// Need to add stuff from our HR
Elements--;
if (Elements < MyElementCount)
break;
FullHR:
*/
ForwardingInfo->HADDROffet[Count] = (Num)? atoi(Num): 0;
if (ForwardingInfo->HADDRS[Count][1])
{
if (FOURCHARCONT == 0)
{
if (strlen(ForwardingInfo->HADDRS[Count][1]) == 4)
{
// Convert to 2 char Continent;
Continent = FindContinent(ForwardingInfo->HADDRS[Count][1]);
if (Continent)
{
free(ForwardingInfo->HADDRS[Count][1]);
ForwardingInfo->HADDRS[Count][1] = _strdup(Continent->TwoCharCode);
}
}
}
else
{
if (strlen(ForwardingInfo->HADDRS[Count][1]) == 2)
{
// Convert to 4 char Continent;
Continent = FindContinent(ForwardingInfo->HADDRS[Count][1]);
if (Continent)
{
free(ForwardingInfo->HADDRS[Count][1]);
ForwardingInfo->HADDRS[Count][1] = _strdup(Continent->FourCharCode);
}
}
}
}
free(SaveHText);
HText++;
Count++;
}
ForwardingInfo->HADDRS[Count] = NULL;
}
VOID SetupHAddresesP(struct BBSForwardingInfo * ForwardingInfo)
{
int Count=0;
char ** HText = ForwardingInfo->HaddressesP;
char * SaveHText, * ptr2;
// char * TopElement;
char * Num;
struct Continent * Continent;
ForwardingInfo->HADDRSP = zalloc(sizeof(void *)); // always NULL entry on end even if no values
while(HText[0])
{
int Elements = 1;
ForwardingInfo->HADDRSP = realloc(ForwardingInfo->HADDRSP, (Count+2) * sizeof(void *));
ForwardingInfo->HADDRSP[Count] = zalloc(2 * sizeof(void *)); // Always at lesat WWW and NULL
SaveHText = _strdup(HText[0]);
Num = strlop(SaveHText, ',');
ptr2 = SaveHText + strlen(SaveHText) -1;
ForwardingInfo->HADDRSP[Count][0] = _strdup(WW);
if (strcmp(HText[0], "WW") != 0)
{
do
{
ForwardingInfo->HADDRSP[Count] = realloc(ForwardingInfo->HADDRSP[Count], (Elements+2) * sizeof(void *));
while ((*ptr2 != '.') && (ptr2 > SaveHText))
{
ptr2 --;
}
if (ptr2 == SaveHText)
{
// End
ForwardingInfo->HADDRSP[Count][Elements++] = _strdup(ptr2);
break;
}
ForwardingInfo->HADDRSP[Count][Elements++] = _strdup(ptr2+1);
*ptr2 = 0;
} while(TRUE);
}
ForwardingInfo->HADDRSP[Count][Elements++] = NULL;
if (ForwardingInfo->HADDRSP[Count][1])
{
if (FOURCHARCONT == 0)
{
if (strlen(ForwardingInfo->HADDRSP[Count][1]) == 4)
{
// Convert to 2 char Continent;
Continent = FindContinent(ForwardingInfo->HADDRSP[Count][1]);
if (Continent)
{
free(ForwardingInfo->HADDRSP[Count][1]);
ForwardingInfo->HADDRSP[Count][1] = _strdup(Continent->TwoCharCode);
}
}
}
else
{
if (strlen(ForwardingInfo->HADDRSP[Count][1]) == 2)
{
// Convert to 4 char Continent;
Continent = FindContinent(ForwardingInfo->HADDRSP[Count][1]);
if (Continent)
{
free(ForwardingInfo->HADDRSP[Count][1]);
ForwardingInfo->HADDRSP[Count][1] = _strdup(Continent->FourCharCode);
}
}
}
}
free(SaveHText);
HText++;
Count++;
}
ForwardingInfo->HADDRSP[Count] = NULL;
}
VOID CheckAndSend(struct MsgInfo * Msg, CIRCUIT * conn, struct UserInfo * bbs)
{
struct BBSForwardingInfo * ForwardingInfo = bbs->ForwardingInfo;
if (ForwardToMe || _stricmp(bbs->Call, BBSName) != 0) // Don't forward to ourself - already here! (unless ForwardToMe set)
{
if ((conn == NULL) || (!(conn->BBSFlags & BBS) || (_stricmp(conn->UserPointer->Call, bbs->Call) != 0))) // Dont send back
{
set_fwd_bit(Msg->fbbs, bbs->BBSNumber);
ForwardingInfo->MsgCount++;
if (ForwardingInfo->SendNew)
ForwardingInfo->FwdTimer = ForwardingInfo->FwdInterval - (2 + (rand() % 30)); //Short delay to prevent all starting at once
}
}
else
{
// if User has Redirect to RMS set do it.
struct UserInfo * user = LookupCall(Msg->to);
if (user && user->flags & F_RMSREDIRECT)
{
user = FindBBS("RMS");
if (user)
{
CheckAndSend(Msg, conn, user);
}
Logprintf(LOG_BBS, conn, '?', "Message matches this BBS and RMS Redirect set - fwd to RMS");
}
else
Logprintf(LOG_BBS, conn, '?', "Message matches this BBS and ForwardToMe not set - not queuing message");
}
}
VOID UpdateB2Dest(struct MsgInfo * Msg, char * Alias)
{
int FileSize;
char MsgFile[MAX_PATH];
FILE * hFile;
char * MsgBytes;
struct stat STAT;
sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number);
if (stat(MsgFile, &STAT) == -1)
return;
FileSize = STAT.st_size;
hFile = fopen(MsgFile, "rb");
if (hFile == NULL)
return;
MsgBytes=malloc(FileSize + 100); // A bit of space for alias substitution on B2
fread(MsgBytes, 1, FileSize, hFile);
fclose(hFile);
if (MsgBytes)
{
char * To, * AT, * ATEND;
To = strstr(MsgBytes, "To:");
if (To)
{
ATEND = strchr(To, '\r');
if (ATEND)
{
size_t i = ATEND - To;
AT = memchr(To, '@', i);
if (AT)
{
// Move Message up/down to make room for substitution
size_t Diff = (ATEND - AT - 1) - strlen(Alias);
size_t BeforeAT = AT - MsgBytes + 1;
int j = 0;
memmove(AT + 1, AT + Diff + 1, Msg->length - BeforeAT + 10);
memcpy(AT + 1, Alias, strlen(Alias));
j = 1;
Msg->length -= (int)Diff;
// Write Back
hFile = fopen(MsgFile, "wb");
if (hFile == NULL)
return;
fwrite(MsgBytes, 1, Msg->length, hFile);
fclose(hFile);
}
}
}
}
}
int MatchMessagetoBBSList(struct MsgInfo * Msg, CIRCUIT * conn)
{
struct UserInfo * bbs;
struct UserInfo * user;
struct BBSForwardingInfo * ForwardingInfo;
char ATBBS[41]="";
char RouteElements[41];
int Count = 0;
char * HElements[20] = {NULL};
int Elements = 0;
char * ptr2;
int MyElement = 0;
BOOL Flood = FALSE;
char FullRoute[100];
struct Continent * Continent;
struct Country * Country;
struct ALIAS * Alias;
struct UserInfo * RMS;
int toLen;
if (Msg->status == 'K')
return 1; // No point, but don't want no route warning
strcpy(RouteElements, Msg->via);
Logprintf(LOG_BBS, conn, '?', "Msg %d Routing Trace To %s Via %s", Msg->number, Msg->to, RouteElements);
// "NTS" Alias substitution is now done on P and T before any other processing
// No, Not a good idea to use same aliss file for NTS and other messages
// (What about OT 2*?)
// If we need to alias other types, add a new file
if (strchr(RouteElements, '!')) // Source Route ("Bang Routing")
{
char * bang = &RouteElements[strlen(RouteElements)];
while (*(--bang) != '!'); // Find last !
*(bang) = 0; // remove it;
_strupr(++bang);
strcpy(Msg->via, RouteElements); // Remove from via
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
if (_stricmp(bbs->Call, bang) == 0)
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace Source Route via %s", bbs->Call);
CheckAndSend(Msg, conn, bbs);
return 1;
}
}
if (conn && !(conn->BBSFlags & BBS))
nodeprintf(conn, "Routing via %s requested but %s not known to this BBS\r", bang, bang);
Logprintf(LOG_BBS, conn, '?', "Routing via %s requested but %s not known to this BBS", bang, bang);
}
if (Msg->type == 'T')
{
strlop(RouteElements, '.');
Alias = CheckForNTSAlias(Msg, RouteElements);
if (Alias)
{
// Replace the AT in the message with the Alias
Logprintf(LOG_BBS, conn, '?', "Routing Trace @%s taken from Alias File", Alias->Alias);
strcpy(Msg->via, Alias->Alias);
if (Msg->B2Flags & B2Msg)
UpdateB2Dest(Msg, Alias->Alias);
SaveMessageDatabase();
}
strcpy(RouteElements, Msg->via); // May have changed
}
// See if AMPR.ORG Mail
// Note message is probably already queued to SMTP or RMS
// If for our domain leave here
toLen = (int)strlen(Msg->via);
if (_memicmp(&Msg->via[toLen - 8], "ampr.org", 8) == 0)
{
// message is for ampr.org
char toCall[48];
char * via;
strcpy(toCall, _strupr(Msg->via));
via = strlop(toCall, '@');
if (via == NULL)
{
// To and VIA already set up. This should only happen if message is for us
Logprintf(LOG_BBS, conn, '?', "Routing Trace at %s is for us. Leave Here", AMPRDomain);
return 1;
}
if (_stricmp(via, AMPRDomain) == 0)
{
// message is for us. Leave Here
if (strlen(toCall) > 6)
toCall[6] = 0;
strcpy(Msg->to, toCall);
strcpy(Msg->via, via);
Logprintf(LOG_BBS, conn, '?', "Routing Trace at %s is for us. Leave Here", AMPRDomain);
return 1;
}
if (SendAMPRDirect)
{
// We want to send ampr mail direct to host. Queue to BBS AMPR
bbs = FindAMPR();
if (bbs)
{
// We have bbs AMPR
if (_stricmp(Msg->to, "RMS") == 0 || Msg->to[0] == 0)
{
// Was set to go via RMS or ISP - change it
strcpy(Msg->to, "AMPR");
}
Logprintf(LOG_BBS, conn, '?', "Routing Trace to ampr.org Matches BBS AMPR");
set_fwd_bit(Msg->fbbs, bbs->BBSNumber);
bbs->ForwardingInfo->MsgCount++;
if (bbs->ForwardingInfo->SendNew)
bbs->ForwardingInfo->FwdTimer = bbs->ForwardingInfo->FwdInterval;
return 1;
}
// To AMPR, but don't have a BBS called AMPR - dropthrough in case we are forwarding AMPR to another BBS
}
}
// See if sending @ winlink.org
if (_stricmp(Msg->to, "RMS") == 0)
{
// If a user of this bbs with Poll RMS set, leave it here - no point in sending to winlink
// To = RMS could come from RMS:EMAIL Address. If so, we only check user if @winlink.org, or
// we will hold g8bpq@g8bpq.org.uk
char * Call;
char * AT;
Call = _strupr(_strdup(Msg->via));
AT = strlop(Call, '@');
if (AT)
{
if (_stricmp(AT, "WINLINK.ORG") == 0)
{
user = LookupCall(Call);
if (user)
{
if (user->flags & F_POLLRMS)
{
Logprintf(LOG_BBS, conn, '?', "Message @ winlink.org, but local RMS user - leave here");
strcpy(Msg->to, Call);
strcpy(Msg->via, AT);
free(Call);
if (user->flags & F_BBS) // User is also a BBS, so set FWD bit so he can get it
set_fwd_bit(Msg->fbbs, user->BBSNumber);
return 1;
}
}
}
}
free(Call);
// To = RMS, but not winlink.org, or not local user.
RMS = FindRMS();
if (RMS)
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace to RMS Matches BBS RMS");
set_fwd_bit(Msg->fbbs, RMS->BBSNumber);
RMS->ForwardingInfo->MsgCount++;
if (RMS->ForwardingInfo->SendNew)
RMS->ForwardingInfo->FwdTimer = RMS->ForwardingInfo->FwdInterval;
return 1;
}
// To RMS, but don't have a BBS called RMS - dropthrough in case we are forwarding RMS to another BBS
}
if (_stricmp(RouteElements, "WINLINK.ORG") == 0)
{
user = LookupCall(Msg->to);
if (user)
{
if (user->flags & F_POLLRMS)
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace @ winlink.org, but local RMS user - leave here");
if (user->flags & F_BBS) // User is also a BBS, so set FWD bit so he can get it
set_fwd_bit(Msg->fbbs, user->BBSNumber);
return 1; // Route found
}
}
RMS = FindRMS();
if (RMS)
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace @ winlink.org Matches BBS RMS");
set_fwd_bit(Msg->fbbs, RMS->BBSNumber);
RMS->ForwardingInfo->MsgCount++;
if (RMS->ForwardingInfo->SendNew)
RMS->ForwardingInfo->FwdTimer = RMS->ForwardingInfo->FwdInterval;
return 1;
}
Logprintf(LOG_BBS, conn, '?', "Routing Trace - @ winlink.org but no BBS RMS");
return 0;
}
// See if a well-known alias
Alias = FindAlias(RouteElements);
if (Alias)
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace Alias Substitution %s > %s",
RouteElements, Alias->Alias);
strcpy(RouteElements, Alias->Alias);
if (conn)
if ((ReaddressReceived && (conn->BBSFlags & BBS)) || (ReaddressLocal && ((conn->BBSFlags & BBS) == 0)))
strcpy(Msg->via, Alias->Alias);
}
// Make sure HA is complete (starting at WW)
if (RouteElements[0] == 0)
{
// Just a TO. If a Bull, set flood
if (Msg->type == 'B')
Flood = TRUE;
goto NOHA;
}
ptr2 = RouteElements + strlen(RouteElements) - 1;
while ((*ptr2 != '.') && (ptr2 > RouteElements))
{
ptr2 --;
}
if (ptr2 != RouteElements)
*ptr2++;
if ((strcmp(ptr2, "WW") == 0) || (strcmp(ptr2, "WWW") == 0))
{
strcpy(FullRoute, RouteElements);
goto FULLHA;
}
if (FindContinent(ptr2))
{
// Just need to add WW
sprintf_s(FullRoute, sizeof(FullRoute),"%s.WW", RouteElements);
goto FULLHA;
}
Country = FindCountry(ptr2);
if (Country)
{
// Just need to add Continent and WW
if (FOURCHARCONT == 0)
sprintf_s(FullRoute, sizeof(FullRoute),"%s.%s.WW", RouteElements, Country->Continent2);
else
sprintf_s(FullRoute, sizeof(FullRoute),"%s.%s.WW", RouteElements, Country->Continent4);
goto FULLHA;
}
// Don't know
// Assume a local dis list, and set Flood.
strcpy(FullRoute, RouteElements);
if (Msg->type == 'B')
Flood = TRUE;
FULLHA:
strcpy(ATBBS, FullRoute);
strlop(ATBBS, '.');
if (FullRoute)
{
// Split it up
ptr2 = FullRoute + strlen(FullRoute) - 1;
do
{
while ((*ptr2 != '.') && (ptr2 > FullRoute))
{
ptr2 --;
}
if (ptr2 != FullRoute)
*ptr2++ = 0;
HElements[Elements++] = ptr2;
} while(Elements < 20 && ptr2 != FullRoute); // Just in case!
}
if (HElements[1])
{
if (FOURCHARCONT == 0)
{
if (strlen(HElements[1]) == 4)
{
// Convert to 2 char Continent;
Continent = FindContinent(HElements[1]);
if (Continent)
{
// free(MyElements[1]);
HElements[1] = _strdup(Continent->TwoCharCode);
}
}
}
else
{
if (strlen(HElements[1]) == 2)
{
// Convert to 4 char Continent;
Continent = FindContinent(HElements[1]);
if (Continent)
{
// free(MyElements[1]);
HElements[1] = _strdup(Continent->FourCharCode);
}
}
}
}
// if Bull, see if reached right area
if (Msg->type == 'B')
{
int i = 0;
// Log My HA for debugging
Logprintf(LOG_BBS, conn, '?', "Routing Trace. Check if reached correct area My HA is %s", HRoute);
// All elements of Helements must match Myelements
while (MyElements[i] && HElements[i]) // Until one set runs out
{
if (strcmp(MyElements[i], HElements[i]) != 0)
break;
i++;
}
// if HElements[i+1] = NULL, have matched all
if (HElements[i] == NULL)
Flood = TRUE;
}
NOHA:
Logprintf(LOG_BBS, conn, '?', "Routing Trace Type %c %sTO %s VIA %s Route On %s %s %s %s %s",
Msg->type, (Flood) ? "(Flood) ":"", Msg->to, Msg->via, HElements[0],
HElements[1], HElements[2], HElements[3], HElements[4]);
if (Msg->type == 'T')
{
int depth = 0;
int bestmatch = -1;
struct UserInfo * bestbbs = NULL;
// if NTS Traffic. Route on Wildcarded TO (best match).
// If no match, route on AT (Should be NTSxx)
// If no match, send to any BBS with routing to state XX and NTS flag set (no we dont!)
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
ForwardingInfo = bbs->ForwardingInfo;
depth = CheckBBSToForNTS(Msg, ForwardingInfo);
if (depth > -1)
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace NTS Matches TO BBS %s Length %d", bbs->Call, depth);
if (depth > bestmatch)
{
bestmatch = depth;
bestbbs = bbs;
}
}
}
if (bestbbs)
{
if (bestbbs->flags & F_NTSMPS)
Logprintf(LOG_BBS, conn, '?', "Routing Trace NTS Best Match is %s, but NTS MPS Set so not queued", bestbbs->Call);
else
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace NTS Best Match is %s", bestbbs->Call);
CheckAndSend(Msg, conn, bestbbs);
}
return 1;
}
// Check AT
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
ForwardingInfo = bbs->ForwardingInfo;
if (CheckBBSAtList(Msg, ForwardingInfo, ATBBS))
{
if (bbs->flags & F_NTSMPS)
Logprintf(LOG_BBS, conn, '?', "Routing Trace NTS %s Matches AT %s, but NTS MPS Set so not queued", ATBBS, bbs->Call);
else
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace NTS %s Matches AT %s", ATBBS, bbs->Call);
CheckAndSend(Msg, conn, bbs);
}
return 1;
}
}
goto CheckWildCardedAT;
}
// First check P message to multiple destinations
// We should choose the BBS with most matching elements (ie match on #23.GBR better that GBR)
// If SendPtoMultiple is set I think we send to any with same match level
// So if SendPtoMultiple is set I think I need to find the best depth then send to all with the same depth
// If none are found on HA match drop through.
// But this means a message at the @BBS call will be forwarded without checking the Implied AT. So do that first
if (SendPtoMultiple && Msg->type == 'P')
{
struct UserInfo * bestbbs = NULL;
int bestmatch = 0;
int depth;
int Matched = 0;
int MultiPDepth = 0;
Count = 0;
Logprintf(LOG_BBS, conn, '?', "SendPtoMultiple is set. Checking for best match level");
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
ForwardingInfo = bbs->ForwardingInfo;
// Check Implied AT
if ((strcmp(ATBBS, bbs->Call) == 0)) // @BBS = BBS
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace %s Matches implied AT %s", ATBBS, bbs->Call);
CheckAndSend(Msg, conn, bbs);
return 1;
}
depth = CheckBBSHElements(Msg, bbs, ForwardingInfo, ATBBS, &HElements[0]);
if (depth)
{
if (depth > MultiPDepth)
{
MultiPDepth = depth;
bestbbs = bbs;
}
}
}
if (MultiPDepth)
{
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
ForwardingInfo = bbs->ForwardingInfo;
depth = CheckBBSHElements(Msg, bbs, ForwardingInfo, ATBBS, &HElements[0]);
if (depth == MultiPDepth)
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace HR Matches BBS %s Depth %d", bbs->Call, depth);
CheckAndSend(Msg, conn, bbs);
Count++;
}
}
return Count;
}
else
Logprintf(LOG_BBS, conn, '?', "SendPtoMultiple is set but no match on HA");
}
if (Msg->type == 'P' || Flood == 0)
{
// P messages are only sent to one BBS, but check the TO and AT of all BBSs before routing on HA,
// and choose the best match on HA
// now has option to send P messages to more than one BBS
struct UserInfo * bestbbs = NULL;
int bestmatch = 0;
int depth;
int Matched = 0;
int MultiPDepth = 0;
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
ForwardingInfo = bbs->ForwardingInfo;
if (ForwardingInfo->PersonalOnly && (Msg->type != 'P') && (Msg->type != 'T'))
continue;
if (CheckBBSToList(Msg, bbs, ForwardingInfo))
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace TO %s Matches BBS %s", Msg->to, bbs->Call);
CheckAndSend(Msg, conn, bbs);
Matched++;
if (SendPtoMultiple && Msg->type == 'P')
continue;
return 1;
}
}
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
ForwardingInfo = bbs->ForwardingInfo;
if (ForwardingInfo->PersonalOnly && (Msg->type != 'P'))
continue;
// Check implied AT
if ((strcmp(ATBBS, bbs->Call) == 0)) // @BBS = BBS
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace %s Matches implied AT %s", ATBBS, bbs->Call);
CheckAndSend(Msg, conn, bbs);
Matched++;
if (SendPtoMultiple && Msg->type == 'P')
continue;
return 1;
}
// Check AT
if (CheckBBSAtList(Msg, ForwardingInfo, ATBBS))
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace %s Matches AT %s", ATBBS, bbs->Call);
CheckAndSend(Msg, conn, bbs);
Matched++;
if (SendPtoMultiple && Msg->type == 'P')
continue;
return 1;
}
}
if (Matched)
{
// Should only get here if Sending P to Multiples is enabled
// and we have at least one forward.
return 1;
}
// Normal HA match (not SendPToMultiple)
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
ForwardingInfo = bbs->ForwardingInfo;
if (ForwardingInfo->PersonalOnly && (Msg->type != 'P'))
continue;
depth = CheckBBSHElements(Msg, bbs, ForwardingInfo, ATBBS, &HElements[0]);
if (depth)
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace HR Matches BBS %s Depth %d", bbs->Call, depth);
if (depth > bestmatch)
{
bestmatch = depth;
bestbbs = bbs;
}
}
}
if (bestbbs)
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace HR Best Match is %s", bestbbs->Call);
CheckAndSend(Msg, conn, bestbbs);
return 1;
}
// Check for wildcarded AT address
// if (ATBBS[0] == 0)
// return FALSE; // no AT
CheckWildCardedAT:
depth = 0;
bestmatch = -1;
bestbbs = NULL;
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
ForwardingInfo = bbs->ForwardingInfo;
if (ForwardingInfo->PersonalOnly && (Msg->type != 'P'))
continue;
depth = CheckBBSATListWildCarded(Msg, ForwardingInfo, ATBBS);
if (depth > -1)
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace Wildcarded AT Matches %s Length %d", bbs->Call, depth);
if (depth > bestmatch)
{
bestmatch = depth;
bestbbs = bbs;
}
}
}
if (bestbbs)
{
if (Msg->type == 'T' && (bestbbs->flags & F_NTSMPS))
Logprintf(LOG_BBS, conn, '?', "Routing Trace Wildcarded AT Best Match is %s, but NTS Msg and MPS Set so not queued", bestbbs->Call);
else
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace Wildcarded AT Best Match is %s", bestbbs->Call);
CheckAndSend(Msg, conn, bestbbs);
}
return 1;
}
Logprintf(LOG_BBS, conn, '?', "Routing Trace - No Match");
return FALSE; // No match
}
// Flood Bulls go to all matching BBSs in the flood area, so the order of checking doesn't matter
// For now I will only route on AT (for non-hierarchical addresses) and HA
// Ver 1.0.4.2 - Try including TO
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
ForwardingInfo = bbs->ForwardingInfo;
if (ForwardingInfo->PersonalOnly)
continue;
if (CheckBBSToList(Msg, bbs, ForwardingInfo))
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace TO %s Matches BBS %s", Msg->to, bbs->Call);
if (ForwardToMe || _stricmp(bbs->Call, BBSName) != 0) // Dont forward to ourself - already here! (unless ForwardToMe set)
{
set_fwd_bit(Msg->fbbs, bbs->BBSNumber);
ForwardingInfo->MsgCount++;
}
Count++;
continue;
}
if ((strcmp(ATBBS, bbs->Call) == 0) || // @BBS = BBS
CheckBBSAtList(Msg, ForwardingInfo, ATBBS))
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace AT %s Matches BBS %s", Msg->to, bbs->Call);
CheckAndSend(Msg, conn, bbs);
Count++;
continue;
}
if (CheckBBSHElementsFlood(Msg, bbs, ForwardingInfo, Msg->via, &HElements[0]))
{
Logprintf(LOG_BBS, conn, '?', "Routing Trace HR %s %s %s %s %s Matches BBS %s",
HElements[0], HElements[1], HElements[2],
HElements[3], HElements[4], bbs->Call);
CheckAndSend(Msg, conn, bbs);
Count++;
}
}
if (Count == 0)
goto CheckWildCardedAT;
Logprintf(LOG_BBS, conn, '?', "Routing Trace - No Match");
return Count;
}
BOOL CheckBBSToList(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo)
{
char ** Calls;
// Check TO distributions
if (ForwardingInfo->TOCalls)
{
Calls = ForwardingInfo->TOCalls;
while(Calls[0])
{
if (strcmp(Calls[0], Msg->to) == 0)
return TRUE;
Calls++;
}
}
return FALSE;
}
BOOL CheckBBSAtList(struct MsgInfo * Msg, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS)
{
char ** Calls;
// Check AT distributions
// if (strcmp(ATBBS, bbs->Call) == 0) // @BBS = BBS
// return TRUE;
if (ForwardingInfo->ATCalls)
{
Calls = ForwardingInfo->ATCalls;
while(Calls[0])
{
if (strcmp(Calls[0], ATBBS) == 0)
return TRUE;
Calls++;
}
}
return FALSE;
}
int CheckBBSHElements(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS, char ** HElements)
{
// Used for Personal Messages, and Bulls not yot at their target area
char *** HRoutes;
int i = 0, j, k = 0;
int bestmatch = 0;
if (ForwardingInfo->HADDRSP)
{
// Match on Routes
HRoutes = ForwardingInfo->HADDRSP;
k=0;
while(HRoutes[k])
{
i = j = 0;
while (HRoutes[k][i] && HElements[j]) // Until one set runs out
{
if (strcmp(HRoutes[k][i], HElements[j]) != 0)
break;
i++;
j++;
}
// Only send if all BBS elements match
if (HRoutes[k][i] == 0)
{
if (i > bestmatch)
bestmatch = i;
}
k++;
}
}
return bestmatch;
}
int CheckBBSHElementsFlood(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS, char ** HElements)
{
char *** HRoutes;
char ** BBSHA;
int i = 0, j, k = 0;
int bestmatch = 0;
if (ForwardingInfo->HADDRS)
{
// Match on Routes
// Message must be in right area (all elements of message match BBS Location HA)
BBSHA = ForwardingInfo->BBSHAElements;
if (BBSHA == NULL)
return 0; // Not safe to flood
i = j = 0;
while (BBSHA[i] && HElements[j]) // Until one set runs out
{
if (strcmp(BBSHA[i], HElements[j]) != 0)
break;
i++;
j++;
}
if (HElements[j] != 0)
return 0; // Message is not for BBS's area
HRoutes = ForwardingInfo->HADDRS;
k=0;
while(HRoutes[k])
{
i = j = 0;
while (HRoutes[k][i] && HElements[j]) // Until one set runs out
{
if (strcmp(HRoutes[k][i], HElements[j]) != 0)
break;
i++;
j++;
}
if (i > bestmatch)
{
// As Flooding, only match if all elements match, and elements matching > offset
// As Flooding, only match if all elements from BBS are matched
// ie if BBS has #23.gbr.eu, and msg gbr.eu, don't match
// if BBS has gbr.eu, and msg #23.gbr.eu, ok (so long as bbs in in #23, checked above.
if (HRoutes[k][i] == 0)
bestmatch = i;
}
k++;
}
}
return bestmatch;
}
int CheckBBSToForNTS(struct MsgInfo * Msg, struct BBSForwardingInfo * ForwardingInfo)
{
char ** Calls;
char * Call;
char * ptr;
int bestmatch = -1;
int MatchLen = 0;
// Look for Matches on TO using Wildcarded Addresses. Intended for use with NTS traffic, with TO = ZIPCode
// We forward to the BBS with the most specific match - ie minimum *'s in match
if (ForwardingInfo->TOCalls)
{
Calls = ForwardingInfo->TOCalls;
while(Calls[0])
{
BOOL Invert = FALSE; // !Match
Call = Calls[0];
if (Call[0] == '!' || Call[0] == '-')
{
Call++;
Invert = TRUE;
}
ptr = strchr(Call, '*');
if (ptr)
{
MatchLen = ptr - Call;
if (memcmp(Msg->to, Call, MatchLen) == 0)
{
// Match - de we have a better one?
// if it is a !Match, return without checking any more
if (Invert)
return -1;
if (MatchLen > bestmatch)
bestmatch = MatchLen;
}
}
else
{
//no star - just do a normal compare
if (strcmp(Msg->to, Call) == 0)
{
if (Invert)
return -1;
MatchLen = (int)strlen(Call);
if (MatchLen > bestmatch)
bestmatch = MatchLen;
}
}
Calls++;
}
}
return (int)bestmatch;
}
int CheckBBSATListWildCarded(struct MsgInfo * Msg, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS)
{
char ** Calls;
char * Call;
char * ptr;
int bestmatch = -1; // must be signed!
int MatchLen = 0;
// Look for Matches on AT using Wildcarded Addresses. Only applied after all other checks fail. Intended mainly
// for setting a default route, but could have other uses
// We forward to the BBS with the most specific match - ie minimum *'s in match
if (ForwardingInfo->ATCalls)
{
Calls = ForwardingInfo->ATCalls;
while(Calls[0])
{
Call = Calls[0];
ptr = strchr(Call, '*');
// only look if * present - we have already tried routing on the full AT
if (ptr)
{
MatchLen = ptr - Call;
if (memcmp(ATBBS, Call, MatchLen) == 0)
{
// Match - de we have a better one?
if (MatchLen > bestmatch)
bestmatch = MatchLen;
}
}
Calls++;
}
}
return (int)bestmatch;
}
struct ALIAS * CheckForNTSAlias(struct MsgInfo * Msg, char * ATFirstElement)
{
struct ALIAS ** Alias = NTSAliases;
char * Call;
char * ptr;
size_t MatchLen = 0;
// We have a list of wildcarded TO (ie Zip Codes) and corresponding replacement NTSXX
// It seems the NTS people want to match on either TO or DEST, and replace the AT
// and to use only the first matching
while(Alias[0])
{
Call = Alias[0]->Dest;
if (Call == NULL)
break;
ptr = strchr(Call, '*');
if (ptr)
{
MatchLen = ptr - Call;
if (memcmp(Msg->to, Call, MatchLen) == 0)
return(Alias[0]);
}
else
{
//no star - just do a normal compare
if (strcmp(Msg->to, Call) == 0)
return(Alias[0]);
}
// Try AT
if (ATFirstElement && ATFirstElement[0])
{
if (ptr)
{
if (memcmp(ATFirstElement, Call, MatchLen) == 0)
return(Alias[0]);
}
else
{
if (strcmp(ATFirstElement, Call) == 0)
return(Alias[0]);
}
}
Alias++;
}
return NULL;
}
VOID ReRouteMessages()
{
// Pass all messages to the Mail Routing routine.
// Used if a new BBS is set up, or to readdress messages from a failed BBS
struct MsgInfo * Msg;
int n;
char SaveStatus;
char Savefbbs[NBMASK];
for (n = 1; n <= NumberofMessages; n++)
{
Msg = MsgHddrPtr[n];
// if killed, or forwarded and not a bull, ignore
// If status was F and we add anther BBS, set back to N
if (Msg->status == 'K' || (Msg->status == 'F' && Msg->type != 'B'))
continue;
if (Msg->type == 'B')
SaveStatus = Msg->status;
memcpy(Savefbbs, Msg->fbbs, NBMASK);
memset(Msg->fbbs, 0, NBMASK);
MatchMessagetoBBSList(Msg, NULL);
if (memcmp(Savefbbs, Msg->fbbs, NBMASK) != 0)
{
// Have changed Message Routing
// Clear fwd bits on any BBS it has been sent to
if (memcmp(Msg->fbbs, zeros, NBMASK) != 0)
{
struct UserInfo * user;
for (user = BBSChain; user; user = user->BBSNext)
{
if (check_fwd_bit(Msg->fbbs, user->BBSNumber)) // for this BBS?
{
if (check_fwd_bit(Msg->forw, user->BBSNumber)) // Already sent?
clear_fwd_bit(Msg->fbbs, user->BBSNumber);
}
}
// If still some bits set, change to $
if (memcmp(Msg->fbbs, zeros, NBMASK) != 0)
{
if (FirstMessageIndextoForward > n)
FirstMessageIndextoForward = n;
if (Msg->type == 'B')
Msg->status = '$';
}
else
{
// all clear - set to N or F
if (Msg->type == 'B')
{
if (memcmp(Msg->forw, zeros, NBMASK) == 0)
Msg->status = 'N'; // Not sent anywhere, and nowhere to send, so N
else
Msg->status = 'F';
}
}
}
}
}
SaveMessageDatabase();
}