home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 February / PCO_0299.ISO / filesbbs / dos / indigo01.exe / UPLINK.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-26  |  16.1 KB  |  444 lines

  1. // This program is free software; you can redistribute it and/or modify it
  2. // under the terms of the GNU General Public License as published by the Free
  3. // Software Foundation; either version 2 of the License, or (at your option)
  4. // any later version.
  5.  
  6. // You should have received a copy of the GNU General Public License along
  7. // with this program; if not, write to the Free Software Foundation, Inc., 675
  8. // Mass Ave, Cambridge, MA 02139, USA.
  9.  
  10. // uplink.cpp
  11. // Routines for moving outbound Blue Wave packets to a PKT file.
  12.  
  13. #include "uplink.h"
  14. #include "version.h"
  15. #include "debug.h"
  16. #include "string.h"
  17. #include "bluewave.h"
  18. #include "pkthead.h"
  19. #include "shorttag.h"
  20. #include "msgid.h"
  21. #include <time.h>
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #ifdef __EMX__
  25. #include <unistd.h>
  26. #endif
  27.  
  28. #ifdef __LINUX__
  29. #define stricmp strcasecmp
  30. #endif
  31.  
  32. // Class: Uplink
  33. // This is the class for outboundPKT files.
  34.  
  35. // constructor
  36. // Initialize files.
  37. Uplink::Uplink(FidoAddress myAddress, FidoAddress uplinkAddress,
  38.                const char *outboundPath, const char *password, unsigned defZone,
  39.                const char *originstr)
  40. {
  41.     doDEBUG(printf("Uplink::Uplink(%u:%u/%u.%u, %u:%u/%u.%u, \"%s\", \"%s\", %u)\n",
  42.                    myAddress.zone, myAddress.net, myAddress.node, myAddress.point,
  43.                    uplinkAddress.zone, uplinkAddress.net, uplinkAddress.node, uplinkAddress.point,
  44.                    outboundPath, password, defZone));
  45.  
  46.     // Addresses.
  47.     me = myAddress;
  48.     uplink = uplinkAddress;
  49.  
  50.     // Put the netmail area in the list of known areas.
  51.     char nettag[26];
  52.     sprintf(nettag, "[%u.%u.%u.%u]", me.zone, me.net, me.node, me.point);
  53.     tagList_p = new tagList_t;
  54.     tagList_p->truncTag = NULL;
  55.     tagList_p->echoTag = strdup(nettag);
  56.     tagList_p->next = NULL;
  57.  
  58.     // Create the file name for the outbound PKT file. Binkleystyle.
  59.     strncpy(pktFile, outboundPath, sizeof(pktFile));
  60.     pktFile[sizeof(pktFile) - 1] = 0;
  61.     // Is our uplink in another zone than the default? If so, we need to
  62.     // append the zone number to the name of the outbound directory.
  63.     if (uplink.zone != defZone) {
  64.         // If the directory ends with a "\", remove it.
  65.         if ('\\' == pktFile[strlen(pktFile) - 1])
  66.             pktFile[strlen(pktFile) - 1] = 0;
  67.         // And put the zone number in there.
  68.         char zoneExt[8];
  69.         sprintf(zoneExt, ".%03x\\", uplink.zone);
  70.         strcat(pktFile, zoneExt);
  71.     }
  72.     else { // Make sure that the directory ends in a "\".
  73.         if ('\\' != outboundPath[strlen(outboundPath) - 1])
  74.             strcat(pktFile, "\\");
  75.     }
  76.     
  77.     // Node number in hex is the base name (either for the packet name,
  78.     // or the point directory).
  79.     char nodeNo[9];
  80.     sprintf(nodeNo, "%04x%04x", uplink.net, uplink.node);
  81.     strcat(pktFile, nodeNo);
  82.     
  83.     // If we have a point number, the base name is the point number.
  84.     if (0 != uplink.point) {
  85.         char pointDir[14];
  86.         sprintf(pointDir, ".pnt\\%08x", uplink.point);
  87.         strcat(pktFile, pointDir);
  88.     }
  89.     
  90.     // The packet name ends in ".out".
  91.     strcat(pktFile, ".out");
  92.  
  93.     doDEBUG(printf("PKT will be created as %s\n", pktFile));
  94.  
  95.     // Create the PKT file.
  96.     createPKT(password);
  97.  
  98.     // Save the Origin line.
  99.     strcpy(origin, originstr);
  100.  
  101.     // MSGID serial number support.
  102.     if (getenv("IDSERVER"))
  103.         msgid_p = new MsgidServ(getenv("IDSERVER"));
  104.     else
  105.         msgid_p = new MsgidStd;
  106. }
  107.  
  108. // method: createPKT
  109. // Creates a PKT file.
  110. void Uplink::createPKT(const char *password)
  111. {
  112.     doDEBUG(printf("Uplink::createPKT(\"%s\")\n", password));
  113.  
  114.     // Create the PKT file, and write the header, if necessary.
  115.     FILE *pktf = fopen(pktFile, "ab+");
  116.     fseek(pktf, 0, SEEK_END);
  117.     if (0 == ftell(pktf)) {
  118.         // New file, create the header.
  119.         time_t timer = time(NULL);
  120.         struct tm *currtime_p = localtime(&timer);
  121.  
  122.         // Put the data in the PKT header record.
  123.         pktheader_t pktheader;
  124.         memset(&pktheader, 0, sizeof(pktheader));
  125.         pktheader.orgnode  = me.node;
  126.         pktheader.dstnode  = uplink.node;
  127.         pktheader.year     = currtime_p->tm_year + 1900;
  128.         if (pktheader.year < 1980) // Just in case we have a year 2000 bug.
  129.             pktheader.year += 100;
  130.         pktheader.month    = currtime_p->tm_mon;
  131.         pktheader.day      = currtime_p->tm_mday;
  132.         pktheader.hour     = currtime_p->tm_hour;
  133.         pktheader.min      = currtime_p->tm_min;
  134.         pktheader.sec      = currtime_p->tm_sec;
  135.         pktheader.pktver   = PKTVER;
  136.         pktheader.orgnet   = me.net;
  137.         pktheader.dstnet   = uplink.net;
  138.         pktheader.prodcodl = NOPRODCODE;
  139.         pktheader.pvmajor  = MAJORREV;
  140.         strncpy((char *) &pktheader.password[0], password,
  141.                 sizeof(pktheader.password));
  142.         pktheader.qorgzone = pktheader.orgzone = me.zone;
  143.         pktheader.qdstzone = pktheader.dstzone = uplink.zone;
  144.         pktheader.capvalid = CAPVALID;
  145.         pktheader.prodcodh = 0;
  146.         pktheader.pvminor  = MINORREV;
  147.         pktheader.capword  = CAPWORD;
  148.         pktheader.orgpoint = me.point;
  149.         pktheader.dstpoint = uplink.point;
  150.         fwrite(&pktheader, sizeof(pktheader), 1, pktf);
  151.  
  152.         // Finish it with two null characters.
  153.         fputc(0, pktf);
  154.         fputc(0, pktf);
  155.     }
  156.     fclose(pktf);
  157. }
  158.  
  159. // destructor
  160. Uplink::~Uplink()
  161. {
  162.     doDEBUG(printf("Uplink[%s]::~Uplink()\n", pktFile));
  163.  
  164.     // Deallocate what we have allocated: the echotaglinst
  165.     tagList_t *trav_p = tagList_p, *next_p;
  166.     while (NULL != trav_p) {
  167.         next_p = trav_p->next;
  168.         if (NULL != trav_p->echoTag)
  169.             free(trav_p->echoTag); // allocated string.
  170.         if (NULL != trav_p->truncTag)
  171.             delete trav_p->truncTag;
  172.         delete trav_p;          // allokerad item.
  173.         trav_p = next_p;
  174.     }
  175.  
  176.     // Deallocat MSGID support.
  177.     delete msgid_p;
  178. }
  179.  
  180. // method: addMessage
  181. // Adds a message, as given in the .upl record, to the PKT file.
  182. void Uplink::addMessage(UPL_HEADER &upl_header, UPL_REC &upl_rec, char *path)
  183. {
  184.     doDEBUG(printf("Uplink[%s]::addMessage(UPL_HEADER, UPL_REC, \"%s\")\n",
  185.             pktFile, path));
  186.  
  187.     doDEBUG(printf("[%s] %s: %s\n", upl_rec.echotag, upl_rec.from,
  188.                    upl_rec.subj));
  189.  
  190.     // If the message is marked as inactive ("deleted" in Blue Wave), we
  191.     // shouldn't do anything with it. And we don't.
  192.     if (upl_rec.msg_attr & UPL_INACTIVE)
  193.         return;
  194.  
  195.     // Set up the PKT message header.
  196.     pktmsg_t msgheader;
  197.     memset(&msgheader, 0, sizeof(msgheader));
  198.     msgheader.pktver  = PKTVER;
  199.     msgheader.orgnode = me.node;
  200.     msgheader.orgnet  = me.net;
  201.     if (upl_rec.msg_attr & UPL_NETMAIL) {
  202.         // With netmail, the destination address of the message is the
  203.         // recipient's.
  204.         msgheader.dstnode = upl_rec.destnode;
  205.         msgheader.dstnet  = upl_rec.destnet;
  206.     }
  207.     else {
  208.         // With echomail, the destination address of the message is the
  209.         // uplink's.
  210.         msgheader.dstnode = uplink.node;
  211.         msgheader.dstnet  = uplink.net;
  212.     }
  213.  
  214.     // Get the time from the Blue Wave message (which is in Unix format),
  215.     // and convert it to the format the PKT file format wants.
  216.     time_t msg_unix_date = upl_rec.unix_date;
  217.     struct tm *msgtime_p = localtime(&msg_unix_date);
  218.     strftime((char *) &msgheader.datetime[0], 20, "%d %b %y  %H:%M:%S",
  219.              msgtime_p);
  220.  
  221.     // -*-Todo: Message attributes-*-
  222.  
  223.     // We need the name of the file with the message in it. We append it
  224.     // to the temporary directory name.
  225.     char filename[256];
  226.     strcpy(filename, path);
  227.     if ('\\' != filename[strlen(filename) - 1])
  228.         strcat(filename, "\\");
  229.     strcat(filename, (char *) &upl_rec.filename[0]);
  230.  
  231.     // Open it.
  232.     FILE *msg = fopen(filename, "rt");
  233.     if (NULL != msg) {
  234.         // If we could open the file, now we want to copy the message to
  235.         // the PKT file.
  236.         FILE *pktf = fopen(pktFile, "rb+");
  237.         if (NULL != pktf) {
  238.             // Now the PKT file is opened, seek to the end of the file,
  239.             // and then back two characters (the PKT file ends with two
  240.             // nulls, which mark the end of the PKT).
  241.             fseek(pktf, 0L, SEEK_END);
  242.             fseek(pktf, -2L, SEEK_CUR);
  243.  
  244.             // Write the PKT message header.
  245.             fwrite(&msgheader, sizeof(msgheader), 1, pktf);
  246.  
  247.             // Write the recipient's and sender's name, and then the subjet.
  248.             fputs((char *) &upl_rec.to[0], pktf);
  249.             fputc(0, pktf);
  250.             fputs((char *) &upl_rec.from[0], pktf);
  251.             fputc(0, pktf);
  252.             fputs((char *) &upl_rec.subj[0], pktf);
  253.             fputc(0, pktf);
  254.  
  255.             // Put some kludges in the message.
  256.             if (upl_rec.msg_attr & UPL_NETMAIL) {
  257.                 // In netmail, we want an INTL kludge, and possibly
  258.                 // TOPT and FMPT kludges.
  259.                 fprintf(pktf, "\x01INTL %u:%u/%u %u:%u/%u\x0d",
  260.                         upl_rec.destzone, upl_rec.destnet, upl_rec.destnode,
  261.                         me.zone, me.net, me.node);
  262.                 if (upl_rec.destpoint)
  263.                     fprintf(pktf, "\x01TOPT %u\x0d", upl_rec.destpoint);
  264.                 if (me.point)
  265.                     fprintf(pktf, "\x01" "FMPT %u\x0d", me.point);
  266.             }
  267.             else {
  268.                 // In echomail, we want an AREA kludge.
  269.                 if (' ' == upl_rec.echotag[0]) // truncated echotag
  270.                     fprintf(pktf, "AREA:%s\x0d",
  271.                             matchLongTag((char *) &upl_rec.echotag[0]));
  272.                 else
  273.                     fprintf(pktf, "AREA:%s\x0d", upl_rec.echotag);
  274.             }
  275.  
  276.             // Create the MSGID kludge (if we don't have a point address,
  277.             // we don't want a .0 on the end (it confuses some software)).
  278.             if (me.point)
  279.                 fprintf(pktf, "\x01MSGID: %u:%u/%u.%u %08lx\x0d",
  280.                         me.zone, me.net, me.node, me.point,
  281.                         msgid_p->getSerial(1));
  282.             else
  283.                 fprintf(pktf, "\x01MSGID: %u:%u/%u %08lx\x0d",
  284.                         me.zone, me.net, me.node,
  285.                         msgid_p->getSerial(1));
  286.  
  287.             // If we have a REPLY kludge in the Blue Wave packet, put it
  288.             // in the PKT file.
  289.             if (!strncmp((char *) &upl_rec.net_dest[0], "REPLY: ", 7))
  290.                 fprintf(pktf, "\x01%s\x0d", upl_rec.net_dest);
  291.  
  292.             // Copy the file, converting line ends to CRs.
  293.             int ch, prevch;
  294.             while (EOF != (ch = fgetc(msg))) {
  295.                 if ('\n' == ch)
  296.                     fputc(13, pktf);
  297.                 else
  298.                     fputc(ch, pktf);
  299.                 prevch = ch;
  300.             }
  301.  
  302.             // End the message with a CR, if there wasn't one.
  303.             if ('\n' != prevch)
  304.                 fputc(13, pktf);
  305.  
  306.             // Put some kludges at the end of the message.
  307.             if (upl_rec.msg_attr & UPL_NETMAIL) {
  308.                 // Netmail:
  309.                 // Put in a Via kludge with the mail reader's name in it.
  310.                 char via[80];
  311.                 strftime(via, sizeof(via), "\x01Via %%u:%%u/%%u.%%u "
  312.                          "@%Y%m%d.%H%M%S %%s %%u.%%02u\x0d",
  313.                          msgtime_p);
  314.                 fprintf(pktf, via, me.zone, me.net, me.node, me.point,
  315.                         upl_header.reader_tear, upl_header.reader_major,
  316.                         upl_header.reader_minor);
  317.  
  318.                 // And another Via kludge, with this program's name in it.
  319.                 time_t timer = time(NULL);
  320.                 struct tm *currtime_p = localtime(&timer);
  321.                 strftime(via, sizeof(via), "\x01Via %%u:%%u/%%u.%%u "
  322.                          "@%Y%m%d.%H%M%S " PROGNAME " " VERSTRING "\x0d",
  323.                          currtime_p);
  324.                 fprintf(pktf, via, me.zone, me.net, me.node, me.point);
  325.             }
  326.             else {
  327.                 // Echomail:
  328.                 // Add a tearline, with this program's name and version
  329.                 fputs("--- " PROGNAME " " VERSTRING, pktf);
  330.                 // and then the name of the mailreader, if there is one.
  331.                 if (upl_header.reader_tear[0])
  332.                     fprintf(pktf, "+%s", (char *) upl_header.reader_tear);
  333.  
  334.                 // And an Origin line. If we don't have one, we don't
  335.                 // write it (naturally).
  336.                 if (origin[0])
  337.                     fprintf(pktf, "\x0d * Origin: %s", origin);
  338.                 else
  339.                     fputs("\x0d * Origin:", pktf);
  340.                 // We end it with the address (in 3D or 4D form).
  341.                 if (me.point)
  342.                     fprintf(pktf, " (%u:%u/%u.%u)\x0d", me.zone, me.net,
  343.                             me.node, me.point);
  344.                 else
  345.                     fprintf(pktf, " (%u:%u/%u)\x0d", me.zone, me.net, me.node);
  346.  
  347.                 // Then some SEEN-BY lines. If we're not a point, we add
  348.                 // both our and our uplink's address to them, otherwise
  349.                 // we only add our own.
  350.                 if (!me.point)
  351.                     fprintf(pktf, "SEEN-BY: %u/%u %u/%u\x0d",
  352.                             me.net, me.node, uplink.net, uplink.node);
  353.                 else
  354.                     fprintf(pktf, "SEEN-BY: %u/%u\x0d",
  355.                             uplink.net, uplink.node);
  356.  
  357.                 // And finally a PATH line.
  358.                 fprintf(pktf, "\x01PATH: %u/%u\x0d", me.net, me.node);
  359.             }
  360.  
  361.             // Finish up.
  362.             fputc(0, pktf);
  363.  
  364.             // And indicate that there is no more messages (yet...)
  365.             fputc(0, pktf);
  366.             fputc(0, pktf);
  367.  
  368.             // Close the files.
  369.             fclose(msg);
  370.             fclose(pktf);
  371.             
  372.             // Delete the reply file.
  373.             remove(filename);
  374.         }
  375.         else {
  376.             fprintf(stderr, "* Unable to write message %s to PKT file %s.\n",
  377.                     filename, pktFile);
  378.         }
  379.  
  380.     }
  381.     else
  382.         fprintf(stderr, "* Unable to open replyfile: %s\n", filename);
  383. }
  384.  
  385. // method: addArea
  386. // Adds an area to the list of known areas for this uplink.
  387. void Uplink::addArea(const char *echoTag)
  388. {
  389.     doDEBUG(printf("Uplink[%s]::addArea(\"%s\")\n", pktFile, echoTag));
  390.  
  391.     // Create an entry for the taglist.
  392.     tagList_t *tagentry_p = new tagList_t;
  393.     tagentry_p->echoTag = strdup(echoTag);
  394.  
  395.     // Truncate the area name if it is too long.
  396.     if (strlen(echoTag) >= sizeof(((INF_AREA_INFO *) NULL)->echotag)) {
  397.         tagentry_p->truncTag = strdup(makeShortTag(echoTag));
  398.         doDEBUG(printf("!! long area name truncated to \"%s\"\n",
  399.                 tagentry_p->truncTag));
  400.     }
  401.     else {
  402.         tagentry_p->truncTag = NULL;
  403.     }
  404.  
  405.     tagentry_p->next = tagList_p->next;
  406.     tagList_p->next = tagentry_p;       // link as number 2 (after netmail)
  407. }
  408.  
  409. // method: isThisYours
  410. // Checks if the echotag is one of those which we recognize.
  411. int Uplink::isThisYours(const char *echoTag)
  412. {
  413.     doDEBUG(printf("Uplink[%s]::isThisYours(\"%s\")\n", pktFile, echoTag));
  414.  
  415.     // Check if we know the area.
  416.     tagList_t *trav_p = tagList_p;
  417.     while (NULL != trav_p) {
  418.         // Check the real tag.
  419.         if (!stricmp(trav_p->echoTag, echoTag))
  420.             return 1;           // match!
  421.         // Check the truncated tag, if any.
  422.         if (NULL != trav_p->truncTag && !stricmp(trav_p->truncTag, echoTag))
  423.             return 1;           // match!
  424.         trav_p = trav_p->next;
  425.     }
  426.  
  427.     return 0;   // no match
  428. }
  429.  
  430. // method: matchLongTag
  431. // Gets a long echotag from a truncated one.
  432. char *Uplink::matchLongTag(char *shortTag)
  433. {
  434.     // Locate the truncated tag in the list
  435.     tagList_t *trav_p = tagList_p;
  436.     while (NULL != trav_p) {
  437.         if (NULL != trav_p->truncTag && !stricmp(trav_p->truncTag, shortTag))
  438.             return trav_p->echoTag; // match!
  439.         trav_p = trav_p->next;
  440.     }
  441.  
  442.     return NULL; // no match
  443. }
  444.