home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 2 BBS / 02-BBS.zip / adept107.zip / SPTH.DOC < prev    next >
Text File  |  1996-01-12  |  24KB  |  755 lines

  1.  
  2.                             ^aSPTH:
  3.  
  4.         A proposal for a 5-D control line for FTN echomail
  5.                      submitted by AdeptSoft
  6.  
  7.  
  8.  
  9. Current FTN echomail carries two primary types of control lines
  10. dedicated to trying to keep track of where a message has been.  One is
  11. the SEEN-BY and the other is the ^aPATH (ref. FTS-0004).  Both of these
  12. control lines are fatally flawed for use in today's Fidonet Technology
  13. Networks, or FTN.  They are only 2-D (two dimensional addressing, or net
  14. and node), while current addressing technology is 5-D (domain, zone,
  15. net, node and point). Also, ^aPATH lines are NOT required.
  16.  
  17.  
  18. What is ^aSPTH?
  19. ---------------
  20.  
  21. The purpose of the proposed ^aSPTH line is to replace the ^aPATH line
  22. with a new, backward compatible 5-D control line that tracks every node
  23. that has processed a message.  This is, of course, the function the
  24. ^aPATH line had until addressing increased beyond 2-D, rendering ^aPATH
  25. useless.
  26.  
  27. What do I mean when I say the ^aPATH line is useless?  Let's assume
  28. there are two nodes, one in Fidonet and one in Funkynet, with the 4-D
  29. address of 1:65500/1.0    A ^aPATH entry for either of these nodes would
  30. be:
  31.  
  32.     65500/1
  33.  
  34. Which node is that?  For both nodes, one following the other, we'd have
  35.  
  36.     65500/1 1
  37.  
  38. Which node is which?
  39.  
  40. This same confusion results from two nodes in the same domain with
  41. identical net and node numbers but different zones.
  42.  
  43. This same confusion happens when a several points which all have the
  44. same net and node.
  45.  
  46. Therefore, it is not safe to use ^aPATH lines to see if a message you've
  47. received has been on your system before, or a system to which you're about
  48. to send the message. (Note that 2-D SEEN-BYs suffer from this same
  49. unreliability, but SEEN-BYs are of such MARGINAL usefulness that they
  50. should be eliminated, except for tiny seenbys for backward compatibility
  51. (which should be ignored), not upgraded.) Moreover, when a dupe loop
  52. arises, as they inevitably do due to faulty topology (read: operator
  53. error), the 2-D nature of ^aPATH lines makes it difficult to examine the
  54. topology map (which is what a ^aPATH line is supposed to be used for)
  55. without making many guesses.  This situation will only worsen as more
  56. and more zones duplicate net numbers extant in other zones, and domains
  57. duplicate zone and net numbers of other domains.  There is nothing
  58. stopping these other zones and domains from doing so, and they should
  59. not have to stop.
  60.  
  61. In short, we need to fix our control information instead.
  62.  
  63. ^aSPTH can usher in a new "era" of networking using Fidonet technology.
  64. It can allow messages to move freely between zones and domains without
  65. losing the value of either the topology map or dupe elimination.  There
  66. are likely to be many other side benefits, such as tracking down domain
  67. or zone gates from the ^aSPTH information.
  68.  
  69. ^aSPTH will allow many artificial restrictions on zone/domain gating to
  70. be removed.  For instance, there will be no need to worry about node
  71. numbers from foreign domains appearing in echomail origin lines (or
  72. origin lines themselves, for that matter).  Points can forward mail just
  73. like "regular" nodes and still be listed in the topology map.  Network
  74. software programmers won't have to worry about where to send a netmail
  75. reply when the ^aMSGID entry is not an FTN address and the FTN domain
  76. name for the foreign net is not obvious from the address portion of the
  77. ^aMSGID.  Dupe producers can be quickly and accurately pinpointed,
  78. reducing tensions between domains.
  79.  
  80.  
  81. What isn't ^aSPTH?
  82. ------------------
  83.  
  84. So much for reasons for existence and benefits.  Here's what it isn't:
  85.  
  86. o  ^aSPTH does not change the format of a packet or the packed message.
  87.    Reference FTS-0001 for more information on the transport layer.
  88.  
  89. o  ^aSPTH is recommended, but not required, for new echomail processors,
  90.    particularly those which serve as zone/domain gates.
  91.  
  92.  
  93. What does an ^aSPTH line look like?
  94. -----------------------------------
  95.  
  96. ^aSPTH lines consist of the following:
  97.  
  98.     1)  The tag "^aSPTH: " (where the ^a represents ASCII code 1). Note
  99.         that ^aSPTH is followed by a colon since FTS-0001 says that it
  100.         should be, although none of FTS-0001's examples are.
  101.  
  102.     2)  One or more 5-D FTN addresses consisting of domain, zone,
  103.         net, node and point (if non-zero) in the format:
  104.  
  105.             Domain#zone:net/node.point
  106.  
  107.  
  108. Control lines should be limited to 79 characters or less per line for
  109. esthethic and obliquely technical reasons.  Addresses are "sticky,"
  110. which is to say that information duplicated top-down by the previous
  111. entry should not be repeated.  For instance, if the first entry's
  112. address is 1:213/760.0@Fidonet and the second is 1:213/100.0@Fidonet, the
  113. ^aSPTH line would be:
  114.  
  115.     ^aSPTH: Fidonet#1:213/760 100
  116.  
  117. If we add third and fourth nodes with the addresses 1:213/780@Funkynet
  118. and 1:213/780.1@Funkynet, the line becomes:
  119.  
  120.     ^aSPTH: Fidonet#1:213/760 100 Funkynet#1:213/780 .1
  121.  
  122. This "stickiness" prevents ^aSPTH lines from becoming too large (which
  123. they surely would without it).  Other examples are given later on if
  124. you're still confused.
  125.  
  126.  
  127.  
  128. When a new message is exported, the ^aSPTH line should be prepended to
  129. the TOP of the message body with the address of the exporting node.  One
  130. address per node, please.
  131.  
  132. When a message is forwarded, any existing ^aPATH line should be merged
  133. to any existing ^aSPTH line (or, if there is no existing ^aSPTH line,
  134. one should be created), and then the ^aPATH line should be discarded.
  135. Since ^aPATH is 2-D you'll have to guess at the domain and zone portions
  136. of the addresses in the ^aPATH line (assume point is always zero).  For
  137. messages with existing ^aSPTH lines, assume the zone and domain have not
  138. changed.  For messages without existing ^aSPTH lines, assume your domain
  139. and zone unless you have knowledge of what the appropriate domain and
  140. zone are.  After assuring that the ^aSPTH line is up to date, add your
  141. exporting FTN address.  By doing this, we can be sure that once zone and
  142. domain gating software utilizes ^aSPTH we will have valid topology maps
  143. even if intermediate nodes do not upgrade (with the possible exception
  144. of points, but points aren't supposed to be forwarding echomail under
  145. the existing system precisely because they're "untraceable.").
  146.  
  147. Remember, ^aSPTH goes at the top of the message body, not the bottom.
  148.  
  149. Like ^aPATH, ^aSPTH only lists systems actually processing a message.
  150. It is the set of sending nodes, and does not include the set of sent-to
  151. nodes.  Like ^aPATH, ^aSPTH lines are specifically NOT sorted.
  152.  
  153. ^aSPTH lines should NEVER be stripped from a message that is or may be
  154. forwarded.
  155.  
  156. Note that it is silly to expect ^aSPTH to contain addresses of foreign
  157. (non-FTN) network nodes; they play by their own set of rules.  Hopefully
  158. they will preserve our ^aSPTH information and not muck with it.
  159.  
  160.  
  161.  
  162. Following are definitions of the parts of an FTN address as used in
  163. a ^aSPTH line:
  164.  
  165.    Domain - A domain is an alphanumeric [A-Z,0-9] series of ASCII
  166.             characters, from one to eight characters long.  Domain names
  167.             MUST begin with an alphabetic character.  They are case
  168.             insensitive. Note that a domain name as used in SPTH is not
  169.             necessarily the same as a domain used on some other network.
  170.             For a common example, "Fidonet" is a valid ^aSPTH domain;
  171.             "Fidonet.org" is not, as it is too long and contains a
  172.             non-alphanumeric character (the period).  Domain names
  173.             should be treated case-insensitively.
  174.  
  175.     Zone  - A zone is a two-byte integer value (represented as unsigned
  176.             decimal for ^aSPTH usage).  Valid values range from 1 to
  177.             65530 (five values are reserved for possibly strange FTSC
  178.             uses).
  179.             A zone is preceded by a pound sign.  ie.  #4
  180.  
  181.     Net   - A net is a two-byte integer value as for Zone above.
  182.             A net is preceded  by a colon. ie.   :213
  183.  
  184.     Node  - A node is a two-byte integer value as for Zone above, except
  185.             that nodes may be numbered 0.  Node 0 rarely shows up in
  186.             echomail, though, since it's usually reserved for a net's
  187.             coordinator and is used for "business" only.
  188.             A node is preceded by a slash if it is not preceded by a space.
  189.             ie.  :213/760   (no space before node number)
  190.             or    760       (space before node number)
  191.  
  192.     Point - A point is a two-byte integer value as for Node above.
  193.             Remember, point shouldn't be listed if it's 0 as 0 is
  194.             always assumed for the point field if it's missing.
  195.             A point is preceded by a period.  ie.  .12
  196.  
  197.  
  198. About backward compatibility:  since ^aSPTH replaces ^aPATH, you might
  199. think that the information that older processors expect, being
  200. "missing," might cause problems.  This is incorrect!!
  201.  
  202. REMEMBER that the ^aPATH line IS OPTIONAL, and only broken software would
  203. crash due to its absence.
  204.  
  205. The ^aPATH lines only possible use at this time, due to its
  206. 2-D nature and the fact that it is not stripped at domain and zone
  207. gates, as are SEEN-BYs, is as a human-only form of information.  ^aSPTH
  208. serves this purpose (as well as others), and does it better.  Nothing
  209. breaks, therefore you have backward compatibility.
  210.  
  211.  
  212.  
  213. ^aPATH vs. ^aSPTH examples.  Note that in all but example #2 the ^aPATH
  214. line is not useable for dupe control (and since ^aPATH is 2-D, you
  215. couldn't even be sure that the addresses in the ^aPATH lines of example
  216. #2 were useable).  This should put an end to the "the control lines will
  217. be too long" argument as well as give you a feel for how ^aSPTH can
  218. allow easy, seamless interdomain and interzone messaging.  It also
  219. points out rather handily how ^aPATH can quickly become hopelessly
  220. confused due to lack of full address information, and gives you a few
  221. more illustrations for clarity.
  222.  
  223.  
  224. Example #1:
  225.  
  226. Route: (lots of zone traversal)
  227. 1:1/1@Fidonet -> 1:1/100@Fidonet -> 1:2/100@Fidonet -> 1:2/1000@Fidonet ->
  228. 1:2/1000.50@Fidonet -> 2:1/1@Fidonet -> 2:1/2@Fidonet -> 3:1/1@Fidonet ->
  229. 3:1/100@Fidonet -> 3:2/1@Fidonet -> 3:2/2@Fidonet
  230.  
  231. ^aPATH 1/1 100 2/100 1000 1/1 2 1 100 2/1 2
  232.  
  233. ^aSPTH: Fidonet#1:1/1 100 :2/100 1000 .50 #2:1/1 2 #3:1/1 100 :2/1 2
  234.  
  235.  
  236. Example #2:
  237.  
  238. Route: (The addresses in the following are all in Fidonet zone 1
  239.         for this example)
  240. 1/1 1/2 1/3 1/4 1/5 1/6 1/7 1/8 1/9 1/10 1/11 1/12 1/13 1/14 1/15
  241. 2/1 2/2 2/3 2/4 2/5 2/6 2/7 2/8 2/9 2/10 2/11 2/12 2/13 2/14 2/15
  242.  
  243. ^aPATH 1/1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 2/1 2 3 4 5 6 7 8 9
  244. ^aPATH 10 11 12 13 14 15
  245.  
  246. ^aSPTH: Fidonet#1:1/1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 :2/1 2 3 4
  247. ^aSPTH: 5 6 7 8 9 10 11 12 13 14 15
  248.  
  249.  
  250. Example #3:
  251.  
  252. Route: (lots of domain traversal; "worst" case)
  253. 1:1/1@Fidonet ->1:1/1.1@Fidonet -> 2:1/1@Fidonet -> 69:69/1@Funkynet ->
  254. 69:69/69@Funkynet -> 1:1/1@Somenet -> 2:1/1@Somenet -> 1:1/1@Othernet ->
  255. 2:1/1@Othernet -> 1:1/1@Thatnet -> 2:1/1@Thatnet -> 1:1/1@Thisnet ->
  256. 2:1/1@Thisnet -> 3:1/2@Fidonet
  257.  
  258. ^aPATH 1/1 1 69/1 69 1/1 1 1 1 1 1 1 1 2
  259.  
  260. ^aSPTH: Fidonet#1:1/1 .1 #2:1/1 Funkynet#69:69/1 69 Somenet#1:1/1 #2:1/1
  261. ^aSPTH: Othernet#1:1/1 #2:1/1 Thatnet#1:1/1 #2:1/1 Thisnet#1:1/1 #2:1/1
  262. ^aSPTH: Fidonet#3:1/2
  263.  
  264.  
  265.  
  266. Finally, an example of how to merge existing ^aPATH lines to an existing
  267. ^aSPTH:
  268.  
  269. Existing message control lines:
  270.  
  271. ^aSPTH: Fidonet#1:1/1
  272. ...
  273. ^aPATH 1/2 3 4/1
  274.  
  275. Message control lines after being processed by ^aSPTH-aware node
  276. 1:5/1.0@Fidonet:
  277.  
  278. ^aSPTH: Fidonet#1:1/1 2 3 :4/1 :5/1
  279.  
  280.  
  281.  
  282.                                 -o-
  283.  
  284.  
  285.     Credits:  Fido and Fidonet are trademarks of Tom Jennings/Fido
  286.                   Software.
  287.               Jeff Rush created echomail.
  288.               Bob Hartman wrote FTS-0004 (it's the Confmail doc).
  289.  
  290.               Mark Kimes for the original draft of this document
  291.  
  292.  
  293. AdeptSoft 
  294.  
  295.  
  296.                    --- example source code ---
  297.  
  298. typedef struct _ADDR
  299. {
  300.     struct _ADDR *next;
  301.     USHORT        zone;
  302.     USHORT        net;
  303.     USHORT        node;
  304.     USHORT        point;
  305.     CHAR         *domain;
  306. } ADDR, *PADDR;
  307.  
  308. typedef struct _PATH
  309. {
  310.     USHORT net;
  311.     USHORT node;
  312. } PATH, *PPATH;
  313.  
  314. PADDR ReadSPTH(char *pNewPath)
  315. {
  316.     PADDR pHeadOfAddressList;
  317.     char  lastp;
  318.     register char *p;
  319.     char *domain     = NULL;
  320.     char *zone       = NULL;
  321.     char *net        = NULL;
  322.     char *node       = NULL;
  323.     char *point      = NULL;
  324.     char *lastdomain = NULL;
  325.     char *lastzone   = NULL;
  326.     char *lastnet    = NULL;
  327.     char *lastnode   = NULL;
  328.     char *lastpoint  = NULL;
  329.  
  330.     if (!pNewPath || !*pNewPath)
  331.         return (NULL);
  332.  
  333.     do
  334.     {
  335.         while (*pNewPath == '\r')
  336.         {
  337.             pNewPath++;
  338.         }
  339.  
  340.         if (!strncmp(pNewPath, "\01SPTH", 5))
  341.         {
  342.             pNewPath += 5;
  343.  
  344.             if (*pNewPath == ':')   // should have colon.. (FTS-0001)
  345.                 pNewPath++;
  346.  
  347.             pNewPath = SkipWhiteSpace(pNewPath);
  348.  
  349.             while (*pNewPath != '\r' && *pNewPath)
  350.             {
  351.                 pNewPath = SkipWhiteSpace(pNewPath);
  352.                 if (isdigit(*pNewPath))
  353.                 {
  354.                     node = pNewPath;
  355.                     pNewPath = ToDelimiter(pNewPath, ". \t\r");
  356.                     if (*pNewPath == '.')
  357.                         continue;
  358.                 }
  359.                 else
  360.                 {
  361.                     switch (*pNewPath)
  362.                     {
  363.                         case '/':
  364.                             node = &pNewPath[1];
  365.                             break;
  366.  
  367.                         case ':':
  368.                             net = &pNewPath[1];
  369.                             break;
  370.  
  371.                         case '#':
  372.                             zone = &pNewPath[1];
  373.                             break;
  374.  
  375.                         case '.':
  376.                             point = &pNewPath[1];
  377.                             pNewPath = ToDelimiter(pNewPath, " \t\r");
  378.                             goto GotPoint;
  379.  
  380.                         default:
  381.                             if (isalpha(*pNewPath))
  382.                                 domain = pNewPath;
  383.                             else
  384.                             {
  385.                                 // This is an error condition
  386.                                 // it signifies a broken mail processor
  387.                                 pNewPath++;
  388.                                 continue;
  389.                             }
  390.                             break;
  391.                     }
  392.                     if (*pNewPath)
  393.                     {
  394.                         pNewPath++;
  395.                         pNewPath = ToDelimiter(pNewPath, "#:/. \t\r");
  396.  
  397.                         if (*pNewPath && strchr("#:/.", *pNewPath))
  398.                         {
  399.                             // still more to address
  400.                             continue;
  401.                         }
  402.                     }
  403.                 }
  404.  
  405.   GotPoint:
  406.  
  407.                 if (domain)
  408.                     lastdomain = domain;
  409.                 else
  410.                     domain = lastdomain;
  411.                 if (zone)
  412.                     lastzone = zone;
  413.                 else
  414.                     zone = lastzone;
  415.                 if (net)
  416.                     lastnet = net;
  417.                 else
  418.                     net = lastnet;
  419.                 if (node)
  420.                     lastnode = node;
  421.                 else
  422.                     node = lastnode;
  423.                 if (point)
  424.                     lastpoint = point;
  425.                 else
  426.                     point = lastpoint;
  427.  
  428.                 if (!domain || !zone || !net || !node)
  429.                 {
  430.                     continue;
  431.                 }
  432.  
  433.                 // Create entry in list of nodes
  434.                 // set pHeadOfAddressList.. etc.
  435.             }
  436.         }
  437.         else
  438.             break;
  439.  
  440.     } while (*pNewPath && lastdomain && *lastdomain);
  441.  
  442.     return (pHeadOfAddressList);
  443. }
  444.  
  445.  
  446. LONG WriteSPTH(PPATH pOldPathInfo,  // array of old 2D path info
  447.                PADDR pSPTHAddrList, // linked list of current SPTH info
  448.                PADDR pMyAddr,       // Pointer to our address
  449.                FILE *pFile)         // where to print info
  450. {
  451.     register int OldPathIndex = 0,
  452.     register int olen = 0;
  453.     register PADDR pCurrAddr;
  454.     int    len        = 0;
  455.     USHORT lastnet    = 0;
  456.     USHORT lastzone   = 0,
  457.     USHORT lastpoint  = 0,
  458.     USHORT lastnode   = 65535U;
  459.     char   temp[32];
  460.     char   oneaddr[80];
  461.     char  *lastdomain = NULL,
  462.     char   changed    = 0;
  463.     long   totallen   = 0L;
  464.  
  465.     *buffer = 0;
  466.     *oneaddr = 0;
  467.  
  468.     pCurrAddr = pSPTHAddrList;
  469.     while (pCurrAddr)
  470.     {
  471.         if (!lastdomain || !*lastdomain || stricmp(pCurrAddr->domain, lastdomain))
  472.         {
  473.             strcat(oneaddr, " ");
  474.             olen++;
  475.             strcat(oneaddr, pCurrAddr->domain);
  476.             olen += strlen(pCurrAddr->domain);
  477.             changed++;
  478.         }
  479.         if (pCurrAddr->zone != lastzone)
  480.         {
  481.             if (changed)
  482.             {
  483.                 strcat(oneaddr, "#");
  484.                 olen++;
  485.             }
  486.             else
  487.             {
  488.                 strcat(oneaddr, " #");
  489.                 olen += 2;
  490.             }
  491.             strcat(oneaddr, ltoa((LONG) pCurrAddr->zone, temp, 10));
  492.             olen += strlen(temp);
  493.             changed++;
  494.         }
  495.         if (pCurrAddr->net != lastnet)
  496.         {
  497.             if (changed)
  498.             {
  499.                 strcat(oneaddr, ":");
  500.                 olen++;
  501.             }
  502.             else
  503.             {
  504.                 strcat(oneaddr, " :");
  505.                 olen += 2;
  506.             }
  507.             strcat(oneaddr, ltoa((LONG) pCurrAddr->net, temp, 10));
  508.             olen += strlen(temp);
  509.             changed++;
  510.         }
  511.         if (pCurrAddr->node != lastnode)
  512.         {
  513.             if (changed)
  514.             {
  515.                 strcat(oneaddr, "/");
  516.                 olen++;
  517.             }
  518.             else
  519.             {
  520.                 strcat(oneaddr, " ");
  521.                 olen++;
  522.             }
  523.             strcat(oneaddr, ltoa((LONG) pCurrAddr->node, temp, 10));
  524.             olen += strlen(temp);
  525.             changed++;
  526.         }
  527.         if (pCurrAddr->point && lastpoint != pCurrAddr->point)
  528.         {
  529.             if (changed)
  530.             {
  531.                 strcat(oneaddr, ".");
  532.                 olen++;
  533.             }
  534.             else
  535.             {
  536.                 strcat(oneaddr, " .");
  537.                 olen += 2;
  538.             }
  539.             strcat(oneaddr, ltoa((LONG) pCurrAddr->point, temp, 10));
  540.             olen += strlen(temp);
  541.             changed++;
  542.         }
  543.  
  544.         if (len + olen > 78)
  545.         {
  546.             totallen += (LONG) fprintf(pFile, "%s\r", buffer);
  547.             len = sprintf(buffer, "\01SPTH:%s", oneaddr);
  548.         }
  549.         else
  550.         {
  551.             if (!len)
  552.             {
  553.                 strcpy(buffer, "\01SPTH:");
  554.                 len = 6;
  555.             }
  556.             strcat(buffer, oneaddr);
  557.             len += olen;
  558.         }
  559.  
  560.         *oneaddr = 0;
  561.         olen = 0;
  562.         changed = 0;
  563.         lastpoint = pCurrAddr->point;
  564.         lastnode = pCurrAddr->node;
  565.         lastnet = pCurrAddr->net;
  566.         lastzone = pCurrAddr->zone;
  567.         if (pCurrAddr->domain && *pCurrAddr->domain)
  568.             lastdomain = pCurrAddr->domain;
  569.         pCurrAddr = pCurrAddr->next;
  570.     }
  571.  
  572.     if (!pOldPathInfo)
  573.         goto SkipOld;
  574.  
  575.     // add old path information. Because of paths 2D information
  576.     // this can only be 'best guess' information
  577.     olen = 0;
  578.     *oneaddr = 0;
  579.     lastpoint = 0;
  580.     changed = 0;
  581.     if (!lastdomain || !*lastdomain)
  582.         lastdomain = pMyAddr->domain;
  583.     if (!lastzone)
  584.         lastzone = pMyAddr->zone;
  585.  
  586.     // do we only have old path information?
  587.     if (pOldPathInfo[OldPathIndex].net && !pSPTHAddrList)
  588.     {
  589.         len = sprintf(buffer, "\01SPTH: %s#%u:%u/%u", lastdomain, lastzone,
  590.                       pOldPathInfo[OldPathIndex].net, pOldPathInfo[OldPathIndex].node);
  591.         lastnet = pOldPathInfo[OldPathIndex].net;
  592.         lastnode = pOldPathInfo[OldPathIndex].node;
  593.         OldPathIndex++;
  594.     }
  595.  
  596.     while (pOldPathInfo[OldPathIndex].net != 0)
  597.     {
  598.         if (pOldPathInfo[OldPathIndex].net != lastnet)
  599.         {
  600.             strcat(oneaddr, " :");
  601.             olen += 2;
  602.             strcat(oneaddr, ltoa((LONG) pOldPathInfo[OldPathIndex].net, temp, 10));
  603.             olen += strlen(temp);
  604.             changed++;
  605.         }
  606.         if (pOldPathInfo[OldPathIndex].node != lastnode)
  607.         {
  608.             if (changed)
  609.             {
  610.                 strcat(oneaddr, "/");
  611.                 olen++;
  612.             }
  613.             else
  614.             {
  615.                 strcat(oneaddr, " ");
  616.                 olen++;
  617.             }
  618.             strcat(oneaddr, ltoa((LONG) pOldPathInfo[OldPathIndex].node, temp, 10));
  619.             olen += strlen(temp);
  620.             changed++;
  621.         }
  622.  
  623.         if (len + olen > 78)
  624.         {
  625.             totallen += (LONG) fprintf(pFile, "%s\r", buffer);
  626.             len = sprintf(buffer, "\01SPTH:%s", oneaddr);
  627.         }
  628.         else
  629.         {
  630.             if (!len)
  631.             {
  632.                 strcpy(buffer, "\01SPTH:");
  633.                 len = 6;
  634.             }
  635.             strcat(buffer, oneaddr);
  636.             len += olen;
  637.         }
  638.  
  639.         *oneaddr = '\0';
  640.         olen     = 0;
  641.         changed  = 0;
  642.  
  643.         lastnet  = pOldPathInfo[OldPathIndex].net;
  644.         lastnode = pOldPathInfo[OldPathIndex].node;
  645.  
  646.         OldPathIndex++;
  647.     }
  648.  
  649.   SkipOld:
  650.  
  651.     // Add in our address
  652.  
  653.     *oneaddr = '\0';
  654.     olen     = 0;
  655.     changed  = 0;
  656.  
  657.     if (!lastdomain || !*lastdomain || stricmp(pMyAddr->domain, lastdomain))
  658.     {
  659.         strcat(oneaddr, " ");
  660.         olen++;
  661.         strcat(oneaddr, pMyAddr->domain);
  662.         olen += strlen(pMyAddr->domain);
  663.         changed++;
  664.     }
  665.     if (pMyAddr->zone != lastzone)
  666.     {
  667.         if (changed)
  668.         {
  669.             strcat(oneaddr, "#");
  670.             olen++;
  671.         }
  672.         else
  673.         {
  674.             strcat(oneaddr, " #");
  675.             olen += 2;
  676.         }
  677.         strcat(oneaddr, ltoa((LONG) pMyAddr->zone, temp, 10));
  678.         olen += strlen(temp);
  679.         changed++;
  680.     }
  681.     if (pMyAddr->net != lastnet)
  682.     {
  683.         if (changed)
  684.         {
  685.             strcat(oneaddr, ":");
  686.             olen++;
  687.         }
  688.         else
  689.         {
  690.             strcat(oneaddr, " :");
  691.             olen += 2;
  692.         }
  693.         strcat(oneaddr, ltoa((LONG) pMyAddr->net, temp, 10));
  694.         olen += strlen(temp);
  695.         changed++;
  696.     }
  697.     if (pMyAddr->node != lastnode)
  698.     {
  699.         if (changed)
  700.         {
  701.             strcat(oneaddr, "/");
  702.             olen++;
  703.         }
  704.         else
  705.         {
  706.             strcat(oneaddr, " ");
  707.             olen++;
  708.         }
  709.         strcat(oneaddr, ltoa((LONG) pMyAddr->node, temp, 10));
  710.         olen += strlen(temp);
  711.         changed++;
  712.     }
  713.     if (pMyAddr->point && lastpoint != pMyAddr->point)
  714.     {
  715.         if (changed)
  716.         {
  717.             strcat(oneaddr, ".");
  718.             olen++;
  719.         }
  720.         else
  721.         {
  722.             strcat(oneaddr, " .");
  723.             olen += 2;
  724.         }
  725.         strcat(oneaddr, ltoa((LONG) pMyAddr->point, temp, 10));
  726.         olen += strlen(temp);
  727.         changed++;
  728.     }
  729.  
  730.     if (len + olen > 78)
  731.     {
  732.         totallen += (LONG) fprintf(pFile, "%s\r", buffer);
  733.         len = sprintf(buffer, "\01SPTH:%s", oneaddr);
  734.     }
  735.     else
  736.     {
  737.         if (!len)
  738.         {
  739.             strcpy(buffer, "\01SPTH:");
  740.             len = 6;
  741.         }
  742.         strcat(buffer, oneaddr);
  743.         len += olen;
  744.     }
  745.  
  746.     *oneaddr = 0;
  747.     olen = 0;
  748.     changed = 0;
  749.  
  750.     if (len)
  751.         totallen += (LONG) fprintf(pFile, "%s\r", buffer);
  752.  
  753.     return totallen;
  754. }
  755.