home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 3 / hamradioversion3.0examsandprograms1992.iso / misc / 9q920411 / forward.c < prev    next >
C/C++ Source or Header  |  1991-03-09  |  24KB  |  849 lines

  1. /* Some of the code in this file was originally based on the following file:
  2.  * gateway.c : Paul Healy, EI9GL, 900818
  3.  *
  4.  * Rewrote forwarding mechanism to use "X-Forwarded-To" paradigm instead of
  5.  * "X-BBS-To", added timer support, etc.  Anders Klemets, SM0RGV, 901009.
  6.  */
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <ctype.h>
  10. #include <time.h>
  11. #include "global.h"
  12. #include "config.h"
  13. #include "bm.h"
  14. #include "mailbox.h"
  15. #include "smtp.h"
  16. #include "cmdparse.h"
  17. #include "proc.h"
  18. #include "socket.h"
  19. #include "timer.h"
  20. #include "usock.h"
  21. #include "netuser.h"
  22. #include "ax25.h"
  23. #include "netrom.h"
  24. #include "nr4.h"
  25. #include "files.h"
  26.  
  27. #define ISPROMPT(s)    (strlen(s) > 1 && s[strlen(s)-2] == '>')
  28. static struct timer fwdtimer;
  29.  
  30. static char *findident __ARGS((char *str, int n, char *result));
  31. static void sendmsg __ARGS((struct mbx *m,int msgn));
  32. static char *mbxtime __ARGS((char *line));
  33. static int fwdinit __ARGS((struct mbx *m));
  34. static char *fwdanybbs __ARGS((struct mbx *m));
  35. static int timeok __ARGS((char *line));
  36. static void fwdtick __ARGS((void *v));
  37. static int isconnbbs __ARGS((struct mbx *m));
  38. static void startfwd __ARGS((int a,void *v1,void *v2));
  39. static int openconn __ARGS((int argc,char *argv[],void *p));
  40. static int sendmsgtobbs __ARGS((struct mbx *m,int msgn,char *dest,int bulletin));
  41. static int makecl __ARGS((struct mbx *m,int msgn,char *dest,char *line,char *subj,int bulletin));
  42. static char *grabtext __ARGS((char *from,char *to,int marker));
  43.  
  44. /***************************************************************************
  45.    findident copies the 'n'th alphanumeric sequence from 'str' to result.
  46.    It returns a ptr to result. It returns "\0" for missing identifier etc.
  47.    Uses isalnum macro to decide on alphanumeric/non-alnum status.
  48. */
  49. static char *
  50. findident(str, n, result)
  51. char *str, *result;
  52. int n;
  53. {
  54.    int count; /* current identifier */
  55.    count = 0;
  56.    *result = '\0';
  57.    while ( (count<n) && (*str!='\0') ) { /* Process alnum or non alnum seq */
  58.       while ( (*str!='\0') && (!isalnum(*str)) ) /* Get rid of ';:.@%"# etc */
  59.          str++;
  60.       if ( (str!='\0') && isalnum(*str) ) { /* this is an alnum seq */
  61.          count++;
  62.          while ( (*str!='\0') && (isalnum(*str) || (*str=='_')) )
  63.             if (count==n)
  64.                *result++ = *str++;
  65.             else str++;
  66.          if (count==n)
  67.             *result = '\0';
  68.          }
  69.       }
  70.    return result;
  71. }
  72. /**************************************************************************/
  73. static void
  74. sendmsg(m,msgn)
  75. struct mbx *m;
  76. int msgn;
  77. {
  78.     char buf[LINELEN], tb[LINELEN], *cp;
  79.     int len, rec = 0;
  80.     long cnt;
  81.     fseek(m->mfile,m->mbox[msgn].start,0);
  82.     cnt = m->mbox[msgn].size;
  83.  
  84.     /* If the data part of the message starts with "R:" the RFC-822
  85.      * headers will not be forwarded. Instead we will add an R:
  86.      * line of our own.
  87.      */
  88.     for(;;) {
  89.         if(fgets(buf,sizeof(buf),m->mfile) == NULLCHAR)
  90.             break;
  91.         cnt -= strlen(buf);
  92.         if(rec == 1) {    /* look at the line following Received: */
  93.              ++rec;
  94.              if((cp = strchr(buf,';')) != NULLCHAR){
  95.               strcpy(tb,cp+1);     /* get the date of receipt */
  96.               ++rec;
  97.              }
  98.         }
  99.         /* The first Received: line is the one that we have added */
  100.         if(!rec && htype(buf) == RECEIVED)
  101.              ++rec;
  102.         if(*buf == '\n') {
  103.              if(rec == 3 && cnt > 1) {
  104.               fread(buf,1,2,m->mfile);
  105.               cnt -= 2;
  106.               if(strncmp(buf,"R:",2) == 0) {
  107.                    pax25(buf,Mycall);
  108.                    if((cp = strchr(buf,'-')) != NULLCHAR)
  109.                     *cp = '\0';    /* remove SSID */
  110.                    usprintf(m->user,"R:%s @%s %s (%s)\nR:",
  111.                     mbxtime(tb),buf,Hostname,Version);
  112.                    break;
  113.               }
  114.              }
  115.              /* Start over, forwarding the RFC-822 headers */
  116.              fseek(m->mfile,m->mbox[msgn].start,0);
  117.              cnt = m->mbox[msgn].size;
  118.              rec = 0;
  119.              break;
  120.         }
  121.        }
  122.     while(rec != 3) {    /* Forward the RFC-822 headers */
  123.         if(fgets(buf,sizeof(buf),m->mfile) == NULLCHAR)
  124.             break;
  125.         cnt -= strlen(buf);
  126.         switch(htype(buf)) {
  127.         case XFORWARD: /* Do not forward the "X-Forwarded-To:" lines */
  128.         case STATUS:   /* Don't forward the "Status:" line either */
  129.              break;
  130.         default:
  131.              usputs(m->user,buf);
  132.         }
  133.         if(*buf == '\n')    /* last header line */
  134.             break;
  135.     }
  136.     do {    /* the rest of the message is treated below */
  137.         len = min(cnt,sizeof(buf)-1);
  138.         if(fread(buf,1,len,m->mfile) != len)
  139.             break;
  140.         cnt -= len;
  141.         buf[len] = '\0';
  142.         usputs(m->user,buf);
  143.     } while(cnt);
  144. }
  145.  
  146. /* Parse a line for date and time in Arpanet format
  147.  * (Day, day Month year hh:mm:ss Zone) and return it in mailbox format
  148.  * (yymmdd/hhmmz)
  149.  */
  150. static char *
  151. mbxtime(line)
  152. char *line;
  153. {
  154.      extern char *Months[];
  155.      static char buf[12];
  156.      char *cp;
  157.      int i, day;
  158.      cp = line;
  159.      while(isspace(*cp))    /* skip initial blanks */
  160.       ++cp;
  161.      if(*cp == '\0')
  162.       return NULLCHAR;
  163.      if(strlen(cp) < 22)
  164.       return NULLCHAR;
  165.      cp += 5;
  166.      day = atoi(cp);
  167.      if(*(++cp) != ' ')
  168.       ++cp;
  169.      ++cp;
  170.      for(i=0; i < 12; ++i)
  171.       if(strnicmp(Months[i],cp,3) == 0)
  172.            break;
  173.      if(i == 12)
  174.       return NULLCHAR;
  175.      sprintf(buf,"%02d%02d%02d/%02d%02d%c",atoi(cp + 4),i,day,atoi(cp + 7),
  176.          atoi(cp + 10), (strnicmp(cp + 16,"GMT",3) &&
  177.                  strnicmp(cp + 16,"UTC",3)) ? ' ' : 'z');
  178.      return buf;
  179. }
  180.      
  181. static char *
  182. grabtext(from, to, marker)
  183. char *from, *to;
  184. int marker;
  185. {
  186.    while (*from!=marker)
  187.       *to++ = *from++;
  188.    *to = '\0';
  189.    return from+1;
  190. }
  191.  
  192. /* Makes a command line and returns -1 if the message cannot be sent. */
  193. static int
  194. makecl(m, msgn, dest, line, subj, bulletin)
  195. struct mbx *m;
  196. int msgn;        /* Message number */
  197. char *dest;        /* Destination address to use instead of To: line */
  198. char *line, *subj;    /* Buffers to keep command line and subject */
  199. int bulletin;        /* True if message is in public message area */
  200. {
  201.    char bid[LINELEN], to[LINELEN], atbbs[LINELEN], from[LINELEN],
  202.     buf[LINELEN], *cp;
  203.    if(m->mfile == NULLFILE)
  204.     return -1;
  205.    if(!bulletin && (m->mbox[msgn].status & BM_READ))
  206.     return -1;    /* the message was already read */
  207.    fseek(m->mfile,m->mbox[msgn].start,0);
  208.    *bid = *to = *atbbs = *from = '\0';
  209.    if(subj != NULLCHAR)
  210.     *subj = '\0';
  211.    m->stype = bulletin ? 'B' : 'P';    /* default to SB or SP */
  212.    while (fgets(buf,sizeof(buf),m->mfile)) {
  213.       if (buf[0] == '\n')
  214.          break; /* envelope finished */
  215.       switch (htype(buf)) {
  216.       case TO:
  217.         /* The following code tries to parse "To: " lines where the
  218.          * address looks like any of the following: "to@atbbs",
  219.          * "<to@atbbs>", "<to%atbbs@host>" and with possible spaces
  220.          * surrounding the '<>' characters.
  221.          */
  222.         if((cp = getaddress(buf,0)) == NULLCHAR)
  223.         break;
  224.         strcpy(to,cp);
  225.         if((cp = strchr(to,'%')) != NULLCHAR) { /* look for a '%' */
  226.          strcpy(atbbs,cp + 1);
  227.          *cp = '\0';    /* "to" ends at the '%' character */
  228.         }
  229.         else {    /* no '%' but maybe a '@'? */
  230.          if((cp = strchr(to,'@')) != NULLCHAR) {
  231.               strcpy(atbbs,cp + 1);
  232.               *cp = '\0';    /* "to" ends at the '@' character */
  233.          }
  234.         }
  235.         if(*atbbs != '\0')        /* either '%' or '@' found */
  236.          /* cut "atbbs" at the first '@' character */
  237.          for(cp = atbbs; *cp != '\0'; ++cp)
  238.               if(*cp == '@') {
  239.                *cp = '\0';
  240.                break;
  241.               }
  242.         /* "to" or "atbbs" should not be more than 6 characters (ALEN).
  243.          * If "to" is too long, it might simply be because the area name
  244.          * is longer than 6 characters, but it might also be because
  245.          * the address on the To: line is in an obscure format that we
  246.          * failed to parse (eg '!' character notation.)
  247.          */
  248.         if(strlen(to) > ALEN) {
  249.         /* Play safe and set "to" and "atbbs" to the area name */
  250.         strcpy(to,m->area);
  251.         strcpy(atbbs,m->area);
  252.               }
  253.         if(*atbbs == '\0')
  254.         strcpy(atbbs,to);
  255.               to[ALEN] = '\0';
  256.         /* Only if the BBS supports "hierarchical routing designators"
  257.          * is the atbbs field allowd to be longer than 6 characters and
  258.          * have dots in it.
  259.          */
  260.         if((m->sid & MBX_HIER_SID) == 0) {
  261.          atbbs[ALEN] = '\0';    /* 6 character limit */
  262.          if((cp = strchr(atbbs,'.')) != NULLCHAR)
  263.               *cp = '\0';    /* cut "atbbs" at first dot */
  264.         }
  265.             break;
  266.       case MSGID:
  267.         /* The following code distinguishes between two different types
  268.          * of Message-IDs: <abcde@callsign.bbs> and <abcde@host.domain>.
  269.          * The first type is converted to $abcde and the second to
  270.          * $abcde_host.domain. This preserves compability with BBSes.
  271.          */
  272.         if((cp = getname(buf)) == NULLCHAR)
  273.          break;
  274.         bid[0] = '$';
  275.         strcpy(&bid[1],cp);
  276.               cp = strchr(bid,'@');
  277.         /* A trailing ".bbs" indicates that the Message-ID was generated
  278.          * from a BBS style message, and not a RFC-822 message.
  279.          */
  280.         if(cp != NULLCHAR && stricmp(&bid[strlen(bid) - 4], ".bbs") == 0)
  281.         *cp = '\0';
  282.         else
  283.         *cp = '_';
  284.         bid[13] = '\0';    /* BIDs should be no longer than 13 bytes */
  285.               break;
  286.       case SUBJECT:
  287.         if(subj != NULLCHAR)
  288.               (void) grabtext(buf+9, subj, '\n');
  289.             break;
  290.       case FROM:
  291.         if((cp = getaddress(buf,0)) != NULLCHAR) {
  292.         findident(cp, 1, from);        /* cp points to from@domain */
  293.         from[ALEN] = '\0';    /* 6 character limit */
  294.         }
  295.             break;
  296.       case XFORWARD:
  297.         if((cp = getaddress(buf,0)) == NULLCHAR)
  298.          break;
  299.         if(stricmp(m->name,cp) == 0)
  300.         /* This message has already been forwarded, abort */
  301.         return -1;
  302.         break;
  303.       case BBSTYPE:
  304.         m->stype = buf[16];
  305.         break;
  306.       default:
  307.         break;
  308.       }
  309.    }
  310.    /* Check for an invalid RFC-822 header */
  311.    if((to[0] == '\0' && ((dest != NULLCHAR && *dest == '\0') ||
  312.       dest == NULLCHAR)) || from[0] == '\0')
  313.     return -1;
  314.  
  315.    if(line != NULLCHAR) {
  316.     if(dest != NULLCHAR && *dest != '\0'){
  317.          /* strip off hierarchical routing designators from the predefined
  318.           * destination address if they are not supported
  319.           */
  320.          if((m->sid & MBX_HIER_SID) == 0 && (cp = strchr(dest,'.')) !=
  321.            NULLCHAR)
  322.         *cp = '\0';
  323.          sprintf(line, "S%c %s < %s ", m->stype, dest, from);
  324.     }
  325.     else
  326.          sprintf(line, "S%c %s @ %s < %s ", m->stype, to, atbbs, from);
  327.     if(bulletin & (m->sid & MBX_SID))
  328.          strcat(line,bid);
  329.     strcat(line,"\n");
  330.    }
  331.    return 0;
  332. }
  333.  
  334. static int /* 0 = ok, -1 = problem so disc */
  335. sendmsgtobbs(m, msgn, dest, bulletin)
  336. struct mbx *m;
  337. int msgn;
  338. char *dest;        /* Optional destination address to override To: line */
  339. int bulletin;
  340. {
  341.    int result = -1;
  342.    char line[64], subj[256];
  343.    if(makecl(m, msgn, dest, line, subj, bulletin) == -1)
  344.     return 0;    /* do not forward this particular message */
  345.    tputs(line);         /* Send mail offer to bbs */
  346.    rip(line);
  347.    usflush(m->user);
  348.    if (recvline (m->user, m->line, MBXLINE) != -1 ) {
  349.       if (m->line[0] == 'O' || m->line[0] == 'o' || (m->sid & MBX_SID) == 0) {
  350.      /* Got 'OK' or any line if the bbs is unsofisticated */
  351.          tprintf("%s\n", subj);
  352.      sendmsg(m,msgn);    /* send the message */
  353.          tputs("/EX\n"); /* was 0x1a */
  354.          usflush(m->user);
  355.            /* get F> for a good deliver */
  356.            while (recvline (m->user, m->line, MBXLINE) != -1 )
  357.         if (ISPROMPT(m->line)) {
  358.             log(m->user,"MBOX bbs mail sent: %s ", line);
  359.             if(bulletin)
  360.                 m->mbox[msgn].status |= BM_FORWARDED;
  361.             else
  362.                 m->mbox[msgn].status |= BM_DELETE;
  363.             m->change = 1;
  364.             result = 0;
  365.             break;
  366.         }
  367.       }
  368.       else { /* OK response not received from bbs */
  369.        if (m->line[0] == 'N' || m->line[0] == 'n') { /* 'NO' respone */
  370.               log(m->user,"MBOX bbs mail refused: %s\n     %s",line,m->line);
  371.         /* Mark refused message as forwarded if it is a bulletin.
  372.          * The message was probably a duplicate. Non-bulletin
  373.          * messages are sent without BID, so they cannot be dected
  374.          * as duplicates. The reason why it was refused is probably
  375.          * because the address was invalid. Retry later.
  376.          */
  377.         if(bulletin){
  378.             m->mbox[msgn].status |= BM_FORWARDED;
  379.             m->change = 1;
  380.         }
  381.           }
  382.             /* should get a F> here */
  383.           while (recvline (m->user, m->line, MBXLINE) != -1 )
  384.               if (ISPROMPT(m->line)) {
  385.                   result = 0;
  386.             break;
  387.               }
  388.       }
  389.    } /* OK or NO here */
  390.    return result;
  391. }
  392.  
  393. /* This is the main entry point for reverse forwarding. It is also used
  394.  * for normal, "forward", forwarding.
  395.  */
  396. int
  397. dorevfwd(argc,argv,p)
  398. int argc;
  399. char *argv[];
  400. void *p;
  401. {
  402.     char oldarea[64], *cp;
  403.     struct mbx *m;
  404.     int i, bulletin, err = 0;
  405.     m = (struct mbx *)p;
  406.     log(m->user,"MBOX forwarding mail to: %s ", m->name);
  407.     /* indicate we are doing reverse forwarding, if we are not already
  408.      * doing normal forwarding.
  409.      */
  410.     if(m->state != MBX_FORWARD)
  411.         m->state = MBX_REVFWD;
  412.     if(fwdinit(m) != -1) {
  413.         strcpy(oldarea,m->area);
  414.         while(!err && fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
  415.             if(*m->line == '-')    /* end of record reached */
  416.                 break;
  417.             rip(m->line);        /* adds extra null at end */
  418.             cp = strchr(m->line,' '); /* remove trailing blanks */
  419.             if(cp != NULLCHAR)
  420.                 *cp = '\0';
  421.             if((cp = strchr(m->line,'\t')) != NULLCHAR)
  422.                 *cp = '\0';
  423.             if(*m->line == '\0' || *m->line == '.')
  424.                 continue;
  425.             changearea(m,m->line);
  426.             bulletin = isarea(m->line);    /* public area */
  427.             /* get the optional destination field, cp will point
  428.              * at null byte if it is missing.
  429.              */
  430.             cp = &m->line[strlen(m->line)] + 1;
  431.             while(*cp != '\0' && isspace(*cp)) /* strip blanks */
  432.                  ++cp;
  433.             for(i=1; i<=m->nmsgs; i++)
  434.                 if(sendmsgtobbs(m, i, cp, bulletin) == -1) {
  435.                     err = 1;    /* abort */
  436.                     break;
  437.                 }
  438.         }
  439.         fclose(m->tfile);
  440.         m->tfile = NULLFILE;
  441.         if(*oldarea != '\0')
  442.             changearea(m,oldarea);
  443.     }
  444.     if(m->state == MBX_FORWARD)
  445.         return 0;
  446.     tprintf("*** Done\n");
  447.     if((m->sid & MBX_RLI_SID))    /* disconnect if it is a W0RLI bbs */
  448.         return domboxbye(0,NULL,m);
  449.     return 0;
  450. }
  451.  
  452. /* Read the forward file for a record for the connected BBS. If found,
  453.  * return 1 if this is the right time to forward, m->tfile is left pointing
  454.  * at the first message area to be forwarded.
  455.  */
  456. static int
  457. fwdinit(m)
  458. struct mbx *m;
  459. {
  460.     char host[80];
  461.     int start = 1;
  462.     if((m->tfile = fopen(Forwardfile,READ_TEXT)) == NULLFILE)
  463.         return -1;
  464.     while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
  465.         if(*m->line == '\n')
  466.             continue;
  467.         /* lines starting with '-' separate the forwarding records */
  468.         if(*m->line == '-') {
  469.             start = 1;
  470.             continue;
  471.         }
  472.         if(start) {
  473.             start = 0;
  474.             /* get the name of this forwarding record */
  475.             findident(m->line,1,host);
  476.             if(stricmp(m->name,host) == 0) {
  477.                 if(!timeok(m->line))
  478.                     break;
  479.                 /* eat the connect command line */
  480.                 fgets(m->line,MBXLINE,m->tfile);
  481.                 return 0;
  482.             }
  483.         }
  484.     }
  485.     fclose(m->tfile);
  486.     m->tfile = NULLFILE;
  487.     return -1;
  488. }
  489. /* Read the forward file for a record for the connected BBS. If found,
  490.  * determine if this is the right time to forward, and return the command
  491.  * line to establish a forwarding connection. m->tfile is left pointing
  492.  * at the first message area to be forwarded.
  493.  */
  494. static char *
  495. fwdanybbs(m)
  496. struct mbx *m;
  497. {
  498.     char host[80];
  499.     int start = 1;
  500.     if(m->tfile == NULLFILE && (m->tfile = fopen(Forwardfile,READ_TEXT))
  501.                     == NULLFILE)
  502.         return NULLCHAR;
  503.     while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
  504.         if(*m->line == '\n')
  505.             continue;
  506.         /* lines starting with '-' separate the forwarding records */
  507.         if(*m->line == '-') {
  508.             start = 1;
  509.             continue;
  510.         }
  511.         if(start) {
  512.             start = 0;
  513.             /* get the name of this forwarding record */
  514.             findident(m->line,1,host);
  515.             strcpy(m->name,host);
  516.             if(!timeok(m->line))
  517.                 continue;    /* too late or too early */
  518.             /* get the connect command line */
  519.             fgets(m->line,MBXLINE,m->tfile);
  520.             return strdup(m->line);
  521.         }
  522.     }
  523.     fclose(m->tfile);
  524.     m->tfile = NULLFILE;
  525.     return NULLCHAR;
  526. }
  527.  
  528. /* get any groups of four digits that specify the begin and ending hours of
  529.  * forwarding. Returns 1 if forwarding may take place.
  530.  */
  531. static int
  532. timeok(line)
  533. char *line;
  534. {
  535.     char hours[80], *now;
  536.     long t;
  537.     int t1, t2, pos = 2;
  538.     findident(line,pos++,hours);
  539.     if(*hours == '\0')
  540.         return 1;    /* no digits default to 0023, ie. anytime */
  541.     time(&t);
  542.     now = ctime(&t) + 11;
  543.     *(now + 2) = '\0';
  544.     while(*hours != '\0') {
  545.         t1 = (*hours - '0') * 10 + (*(hours+1) - '0');
  546.         t2 = (*(hours+2) - '0') * 10 + (*(hours+3) - '0');
  547.         if(atoi(now) >= t1 && atoi(now) <= t2)
  548.             return 1;        /* right in time */
  549.         findident(line,pos++,hours);    /* get next group if any */
  550.     }
  551.     return 0;    /* too early or too late */
  552. }
  553.  
  554. int
  555. dombtimer(argc,argv,p)
  556. int argc;
  557. char *argv[];
  558. void *p;
  559. {
  560.     if(argc < 2){
  561.         tprintf("Forwarding timer: %lu/%lu\n",
  562.         read_timer(&fwdtimer)/1000L,
  563.         dur_timer(&fwdtimer)/1000L);
  564.         return 0;
  565.     }
  566.     fwdtimer.func = (void (*)())fwdtick;/* what to call on timeout */
  567.     fwdtimer.arg = NULL;        /* dummy value */
  568.     set_timer(&fwdtimer,atol(argv[1])*1000L); /* set timer duration */
  569.     start_timer(&fwdtimer);        /* and fire it up */
  570.     return 0;
  571. }
  572.  
  573. int
  574. dombkick(argc,argv,p)
  575. int argc;
  576. char *argv[];
  577. void *p;
  578. {
  579.     fwdtick(NULL);
  580.     return 0;
  581. }
  582.  
  583. /* called when the forward timer expires or explicitly by dombkick() */
  584. static void
  585. fwdtick(v)
  586. void *v;
  587. {
  588.     char *cc, *cp;
  589.     struct mbx *m;
  590.     int i, bulletin, skip = 0;
  591.     /* restart the timer */
  592.     start_timer(&fwdtimer);
  593.     if((m = newmbx()) == NULLMBX)
  594.         return;
  595.     m->user = Curproc->output;
  596.     m->state = MBX_TRYING;
  597.     while((cc = fwdanybbs(m)) != NULLCHAR) {
  598.         if(isconnbbs(m)) /* already connected to this BBS, skip it */
  599.             skip = 1;
  600.         while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR) {
  601.             if(*m->line == '-') {    /* end of record reached */
  602.                 skip = 0;
  603.                 break;
  604.             }
  605.             if((cp = strchr(m->line,' ')) != NULLCHAR)
  606.                 *cp = '\0';
  607.             if((cp = strchr(m->line,'\t')) != NULLCHAR)
  608.                 *cp = '\0';
  609.             if(skip || *m->line == '\0' || *m->line == '.')
  610.                 continue;
  611.             rip(m->line);
  612.             changearea(m,m->line);
  613.             bulletin = isarea(m->line);    /* public area */
  614.             /* check if there are any messages in this area
  615.              * that need to be forwarded.
  616.              */
  617.             for(i=1; i<=m->nmsgs; i++)
  618.                 if(makecl(m, i, NULLCHAR, NULLCHAR, NULLCHAR,
  619.                    bulletin) == 0) {
  620.                     newproc("Mbox forwarding", 2048,
  621.                         startfwd, 0, (void *)cc,
  622.                         (void *)strdup(m->name),0);
  623.                     skip = 1;
  624.                     cc = NULLCHAR;
  625.                     break;
  626.                 }
  627.         }
  628.         free(cc);
  629.     }
  630.     exitbbs(m);
  631. }
  632.  
  633. /* returns 1 if m->name matches the name of another connected mailbox. */
  634. static int
  635. isconnbbs(m)
  636. struct mbx *m;
  637. {
  638.     int i;
  639.     for(i = 0; i < NUMMBX; ++i)
  640.         if(Mbox[i] != NULLMBX && Mbox[i] != m &&
  641.             stricmp(m->name,Mbox[i]->name) == 0)
  642.                 return 1;
  643.     return 0;
  644. }
  645.  
  646. /* possible commands on the command line in the forwarding file */
  647. static struct cmds cfwdcmds[] = {
  648.     "tcp",        openconn,    0, 0, NULLCHAR,
  649.     "telnet",    openconn,    0, 0, NULLCHAR,
  650. #ifdef AX25
  651.     "ax25",        openconn,    0, 0, NULLCHAR,
  652.     "connect",    openconn,    0, 0, NULLCHAR,
  653. #endif
  654. #ifdef NETROM
  655.     "netrom",    openconn,    0, 0, NULLCHAR,
  656. #endif
  657.     NULLCHAR
  658. };
  659.  
  660. /* this function is called whenever the forwarding timer expires */
  661. static void
  662. startfwd(a,v1,v2)
  663. int a;
  664. void *v1, *v2;
  665. {
  666.     struct mbx *m;
  667.     char *cc;
  668.     cc = (char *) v1;
  669.     if((m = newmbx()) == NULLMBX) {
  670.         free(cc);
  671.         free((char *)v2);
  672.         return;
  673.     }
  674.     strcpy(m->name,(char *)v2);
  675.     free((char *)v2);
  676.     m->state = MBX_TRYING;
  677.     /* open the connection, m->user will be the new socket */
  678.     if(cmdparse(cfwdcmds,cc,(void *)m) == -1) {
  679.         free(cc);
  680.         exitbbs(m);
  681.         return;
  682.     }
  683.     free(cc);
  684.     m->state = MBX_FORWARD;
  685.     sockowner(m->user,Curproc);
  686.     close_s(Curproc->output);
  687.     close_s(Curproc->input);
  688.     /* m->user will be closed automatically when this process exits */
  689.     Curproc->output = Curproc->input = m->user;
  690.     /* We'll do our own flushing right before we read input */
  691.     setflush(m->user,-1);
  692.  
  693.     if(fwdinit(m) == -1) {
  694.         /* it is probably not the right time to forward anymore */
  695.         exitbbs(m);
  696.         return;
  697.     }
  698.     /* read the connect script. Lines starting with a dot will be sent
  699.      * to the remote BBS.
  700.      */
  701.     while(fgets(m->line,MBXLINE,m->tfile) != NULLCHAR)
  702.         if(*m->line == '.')
  703.             tputs(m->line + 1);
  704.         else
  705.             break;
  706.     usflush(m->user);
  707.     fclose(m->tfile);
  708.     m->tfile = NULLFILE;
  709.  
  710.     /* read the initial output from the bbs, looking for the SID */
  711.     for(;;) {
  712.         if(recvline(m->user,m->line,MBXLINE) == -1) {
  713.             exitbbs(m);
  714.             return;
  715.         }
  716.         if(ISPROMPT(m->line))
  717.             break;
  718.         if(*m->line == '[') {        /* parse the SID */
  719.             rip(m->line);
  720.             mbx_parse(m);
  721.             continue;
  722.         }
  723.     }
  724.     /* Now sync the two ends as telnet password messes them up */
  725.     if(socklen(m->user,0))        /* discard any remaining input */
  726.         recv_mbuf(m->user,NULL,0,NULLCHAR,0);
  727.  
  728.     /* send our SID if the peer announced its SID */
  729.     if(m->sid & MBX_SID) {
  730.         tputs("[NET-H$]\n");
  731.         usflush(m->user);
  732.         for(;;) {
  733.             if(recvline(m->user,m->line,MBXLINE) == -1) {
  734.                 exitbbs(m);
  735.                 return;
  736.             }
  737.             if(ISPROMPT(m->line))
  738.                 break;
  739.         }
  740.     }
  741.     /* start the actual forwarding */
  742.     dorevfwd(0,NULL,(void *)m);
  743.     /* ask for reverse forwarding or just disconnect */
  744.     if(((m->sid & MBX_SID) && tputs("F>\n") == -1) ||
  745.        (m->sid & MBX_SID) == 0) {
  746.         exitbbs(m);
  747.         close_s(Curproc->output);
  748.         return;
  749.     }
  750.     usflush(m->user);
  751.     /* parse the commands that are are received during reverse
  752.      * forwarding.
  753.      */
  754.     while(recvline(m->user,m->line,MBXLINE) > 0) {
  755.         rip(m->line);
  756.         if(mbx_parse(m) == 2)    /* got the "*** Done" command */
  757.             break;
  758.         tputs("F>\n");
  759.         usflush(m->user);
  760.     }
  761.     exitbbs(m);
  762.     close_s(Curproc->output);
  763. }
  764.  
  765. /* open a network connection based upon information in the cc line.
  766.  * m->user is set to the socket number.
  767.  */
  768. static int
  769. openconn(argc,argv,p)
  770. int argc;
  771. char *argv[];
  772. void *p;
  773. {
  774.     struct mbx *m;
  775.     char sock[MAXSOCKSIZE], *np, alias[AXBUF];
  776.     union sp sp;
  777.     int len;
  778.     m = (struct mbx *)p;
  779.     sp.p = sock;
  780.     if(argc < 2)
  781.         return -1;
  782.     switch(*argv[0]) {
  783.     case 't':
  784.         sp.in->sin_family = AF_INET;
  785.         if((sp.in->sin_addr.s_addr = resolve(argv[1])) == 0)
  786.             return -1;
  787.         /* get the optional port number */
  788.         if(argc > 2)
  789.             sp.in->sin_port = atoi(argv[2]);
  790.         else
  791.             sp.in->sin_port = IPPORT_TELNET;
  792.         if((m->user = socket(AF_INET,SOCK_STREAM,0)) == -1)
  793.             return -1;
  794.         len = sizeof(*sp.in);
  795.         break;
  796. #ifdef AX25
  797.     case 'a':
  798.     case 'c':    /* allow 'c' for 'connect' as well */
  799.         if(argc < 3)
  800.             return -1;
  801.         sp.ax->sax_family = AF_AX25;
  802.         strncpy(sp.ax->iface,argv[1],ILEN); /* the interface name */
  803.         setcall(sp.ax->ax25_addr,argv[2]); /* the remote callsign */
  804.         /* no digipeaters for now, use the "ax25 route add" command */
  805.         if((m->user = socket(AF_AX25,SOCK_STREAM,0)) == -1)
  806.             return -1;
  807.         len = sizeof(*sp.ax);
  808.         break;
  809. #endif /* AX25 */
  810. #ifdef NETROM
  811.     case 'n':
  812.         sp.nr->nr_family = AF_NETROM;
  813.         len = sizeof(*sp.nr);
  814.         if((m->user = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1)
  815.             return -1;
  816.         memcpy(sp.nr->nr_addr.user,Nr4user,AXALEN);
  817.         memcpy(sp.nr->nr_addr.node,Mycall,AXALEN);
  818.         bind(m->user,sp.p,len);
  819.         /* See if the requested destination could be an alias, and
  820.          * use it if it is.  Otherwise assume it is an AX.25
  821.          * address.
  822.          */
  823.         if (putalias(alias,argv[1],0) != -1 &&
  824.             (np = find_nralias(alias)) != NULLCHAR) {
  825.                 memcpy(sp.nr->nr_addr.user,np,AXALEN) ;
  826.                 memcpy(sp.nr->nr_addr.node,np,AXALEN) ;
  827.         }
  828.         else {    /* parse ax25 callsign */
  829.         /* Only the user callsign of the remote station is never
  830.          * used by NET/ROM, but it is needed for the psocket() call.
  831.          */
  832.             setcall(sp.nr->nr_addr.user,argv[1]);
  833.             setcall(sp.nr->nr_addr.node,argv[1]);
  834.         }
  835.         break;
  836. #endif /* NETROM */
  837.     default:
  838.         return -1;
  839.     }
  840.     sockmode(m->user,SOCK_ASCII);
  841.     if(connect(m->user,sp.p,len) == -1) {
  842.         log(m->user,"MBOX forward failed: %s errno %d",
  843.                 sockerr(m->user),errno);
  844.         close_s(m->user);
  845.         return -1;
  846.     }
  847.     return m->user;
  848. }
  849.