home *** CD-ROM | disk | FTP | other *** search
/ Software Recommendations - 1998 Season 1 / DNBCD4.iso / share / DOS / ipxcopy / SRC.ZIP / SRC / TPRX.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-16  |  29.7 KB  |  1,171 lines

  1. /*
  2.  
  3.    TPRX.C
  4.  
  5.    (c) 1996 by Oliver Kraus
  6.  
  7. */
  8.  
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <conio.h>
  12. #include <dos.h>
  13. #include <fcntl.h>
  14. #include <assert.h>
  15. #include "cio.h"
  16. #include "tprx.h"
  17. #include "crc16.h"
  18. #include "crc32.h"
  19. /* #include "debugmem.h" */
  20.  
  21. #define TPRX_ID_STR "receiver: "
  22.  
  23. char *tprx_es_ipx_not_found     = TPRX_ID_STR "ipx not found";
  24. char *tprx_es_socket_table_full = TPRX_ID_STR "socket table full";
  25. char *tprx_es_socket_open       = TPRX_ID_STR "socket already open";
  26. char *tprx_es_out_of_memory     = TPRX_ID_STR "out of memory";
  27.  
  28. /* - - - - - state prototypes  - - - - - - - - - - - - - - - - - - - - - - */
  29.  
  30. void tprx_state_none(tprx_type tprx);
  31. void tprx_state_gen_ack_request(tprx_type tprx);
  32. void tprx_state_chk_ack_request(tprx_type tprx);
  33. void tprx_state_user_check(tprx_type tprx);
  34. void tprx_state_gen_file_start(tprx_type tprx);
  35. void tprx_state_chk_file_start(tprx_type tprx);
  36. void tprx_state_wait_file_start(tprx_type tprx);
  37. void tprx_state_gen_ack_file_start(tprx_type tprx);
  38. void tprx_state_chk_ack_file_start(tprx_type tprx);
  39. void tprx_state_wait_block_start(tprx_type tprx);
  40. void tprx_state_gen_ack_block_start(tprx_type tprx);
  41. void tprx_state_chk_ack_block_start(tprx_type tprx);
  42. void tprx_state_wait_data(tprx_type tprx);
  43. void tprx_state_gen_missed_blocks(tprx_type tprx);
  44. void tprx_state_chk_missed_blocks(tprx_type tprx);
  45. void tprx_state_gen_ack_block_end(tprx_type tprx);
  46. void tprx_state_chk_ack_block_end(tprx_type tprx);
  47. void tprx_state_gen_ack_file_end(tprx_type tprx);
  48. void tprx_state_chk_ack_file_end(tprx_type tprx);
  49. void tprx_state_none2(tprx_type tprx);
  50.  
  51. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  52.  
  53. /*
  54.    allocate pool memory
  55. */
  56. int tprx_OpenPool(tprx_type tprx, size_t b_len, int b_cnt)
  57. {
  58.    int i;
  59.  
  60.    /* check against 16 bit system */
  61.  
  62.    if ( (long)b_len*(long)b_cnt > 65500 )
  63.       return 1;
  64.  
  65.    /* assign parameter */
  66.  
  67.    tprx->b_len = b_len;
  68.    tprx->b_cnt = b_cnt;
  69.    tprx->rx_cnt = b_cnt+TPRX_RX_ADD;
  70.    tprx->b_pool_size = b_cnt*b_len;
  71.  
  72.    /* data buffers for ipx listen process */
  73.  
  74.    tprx->rx_data = (char **)malloc(tprx->rx_cnt*sizeof(char *));
  75.    if ( tprx->rx_data != NULL )
  76.    {
  77.       for( i = 0; i < tprx->rx_cnt; i++ )
  78.          tprx->rx_data[i] = (char *)malloc(tprx->b_len+TP_BLK_INFO_SIZE);
  79.       for( i = 0; i < tprx->rx_cnt; i++ )
  80.          if ( tprx->rx_data[i] == NULL )
  81.             break;
  82.       if ( i >= tprx->rx_cnt )
  83.       {
  84.  
  85.    /* allocate ipx ecb data buffers */
  86.  
  87.          tprx->rx_ecb = (ipx_ecb_struct **)malloc(tprx->rx_cnt*sizeof(ipx_ecb_struct *));
  88.          if ( tprx->rx_ecb != NULL )
  89.          {
  90.             for( i = 0; i < tprx->rx_cnt; i++ )
  91.                tprx->rx_ecb[i] = (ipx_ecb_struct *)malloc(sizeof(ipx_ecb_struct));
  92.             for( i = 0; i < tprx->rx_cnt; i++ )
  93.                if ( tprx->rx_ecb[i] == NULL )
  94.                   break;
  95.             if ( i >= tprx->rx_cnt )
  96.             {
  97.  
  98.    /* clear ecb buffers */
  99.  
  100.                for( i = 0; i < tprx->rx_cnt; i++ )
  101.                {
  102.                   tprx->rx_ecb[i]->inuse = 0;
  103.                   tprx->rx_ecb[i]->cc = 0;
  104.                   tp_set_blk_id(tprx->rx_data[i], TP_ID_NONE);
  105.                }
  106.  
  107.    /* allocate "block available" array */
  108.  
  109.                tprx->b_is_present = (char *)malloc(tprx->b_cnt*sizeof(char));
  110.                if ( tprx->b_is_present != NULL )
  111.                {
  112.  
  113.    /* allocate memory pool */
  114.  
  115.                   tprx->b_pool_ptr = (char *)malloc(tprx->b_pool_size);
  116.                   if ( tprx->b_pool_ptr != NULL )
  117.                   {
  118.    /* allocate missed blocks list */
  119.  
  120.                      tprx->b_missed_list =
  121.                         (short *)malloc(tprx->b_cnt*sizeof(short));
  122.                      if ( tprx->b_missed_list != NULL )
  123.                      {
  124.                         return 1;
  125.                      }
  126.  
  127.    /* deallocate everything, if something went wrong */
  128.  
  129.                      free(tprx->b_pool_ptr);
  130.                      tprx->b_pool_ptr = NULL;
  131.                   }
  132.                   free(tprx->b_is_present);
  133.                   tprx->b_is_present = NULL;
  134.                }
  135.             }
  136.             for( i = 0; i < tprx->rx_cnt; i++ )
  137.                if ( tprx->rx_ecb[i] != NULL )
  138.                   free(tprx->rx_ecb[i]);
  139.             free(tprx->rx_ecb);
  140.             tprx->rx_ecb = NULL;
  141.          }
  142.       }
  143.       for( i = 0; i < tprx->rx_cnt; i++ )
  144.          if ( tprx->rx_data[i] != NULL )
  145.             free(tprx->rx_data[i]);
  146.       free(tprx->rx_data);
  147.       tprx->rx_data = NULL;
  148.    }
  149.    return 0;
  150. }
  151.  
  152. int tprx_IsOk(tprx_type tprx)
  153. {
  154.    assert(tprx != NULL);
  155.    assert(tprx->rx_cnt == tprx->b_cnt+TPRX_RX_ADD);
  156.    assert(tprx->b_cnt*2 < (int)tprx->b_len);
  157.    return 1;
  158. }
  159.  
  160. tprx_type tprx_Open(unsigned short socket)
  161. {
  162.    tprx_type tprx;
  163.  
  164.    if ( ipx_init() == 0 )
  165.    {
  166.       fprintf(stderr, tprx_es_ipx_not_found);
  167.       return NULL;
  168.    }
  169.  
  170.    switch(ipx_open_socket(socket))
  171.    {
  172.       case 0x0fe:
  173.          fprintf(stderr, tprx_es_socket_table_full);
  174.          return NULL;
  175.       case 0x0ff:
  176.          fprintf(stderr, tprx_es_socket_open);
  177.          return NULL;
  178.    }
  179.  
  180.    tprx = (tprx_type)malloc(sizeof(tprx_struct));
  181.    if ( tprx != NULL )
  182.    {
  183.       tprx->flags    = 0;
  184.       tprx->is_ended = 0;
  185.  
  186.       tprx->is_adr_known = 0;
  187.  
  188.       tprx->socket   = socket;
  189.  
  190.       tprx->f_name   = NULL;
  191.       tprx->fp       = NULL;
  192.       tprx->f_len    = 0L;
  193.       tprx->f_pos    = 0L;
  194.       tprx->f_start  = (clock_t)0;
  195.  
  196.       tprx->small_delay = CLOCKS_PER_SEC/2;
  197.       tprx->large_delay = CLOCKS_PER_SEC*2;
  198.  
  199.       tprx->is_aux   = 0;
  200.  
  201.       tprx_SetState(tprx, tprx_state_none);
  202.  
  203.       if ( tprx_OpenPool(tprx, TPRX_B_LEN, TPRX_B_CNT) != 0 )
  204.       {
  205.          tprx->tx_data = (char *)malloc(tprx->b_len+TP_BLK_INFO_SIZE);
  206.          if ( tprx->tx_data != NULL )
  207.          {
  208.             tprx->tx_ecb = (ipx_ecb_struct *)malloc(sizeof(ipx_ecb_struct));
  209.             if ( tprx->tx_ecb != NULL )
  210.             {
  211.                tprx->tx_ecb->inuse = 0;
  212.                tprx->tx_ecb->cc = 0;
  213.                tp_set_blk_id(tprx->tx_data, TP_ID_NONE);
  214.                tprx_ListenAll(tprx);
  215.                return tprx;
  216.             }
  217.             free(tprx->tx_data);
  218.          }
  219.          tprx_ClosePool(tprx);
  220.       }
  221.       free(tprx);
  222.    }
  223.    ipx_close_socket(socket);
  224.    return NULL;
  225. }
  226.  
  227. void tprx_ClosePool(tprx_type tprx)
  228. {
  229.    int i;
  230.  
  231.    assert(tprx != NULL);
  232.  
  233.    free(tprx->b_missed_list);
  234.    tprx->b_missed_list = NULL;
  235.  
  236.    free(tprx->b_pool_ptr);
  237.    tprx->b_pool_ptr = NULL;
  238.  
  239.    free(tprx->b_is_present);
  240.    tprx->b_is_present = NULL;
  241.  
  242.    for( i = 0; i < tprx->rx_cnt; i++ )
  243.       if ( tprx->rx_ecb[i] != NULL )
  244.       {
  245.          ipx_cancel_ecb(tprx->rx_ecb[i]);
  246.          free(tprx->rx_ecb[i]);
  247.       }
  248.    free(tprx->rx_ecb);
  249.    tprx->rx_ecb = NULL;
  250.  
  251.    for( i = 0; i < tprx->rx_cnt; i++ )
  252.       if ( tprx->rx_data[i] != NULL )
  253.          free(tprx->rx_data[i]);
  254.    free(tprx->rx_data);
  255.    tprx->rx_data = NULL;
  256. }
  257.  
  258. void tprx_Close(tprx_type tprx)
  259. {
  260.    assert(tprx != NULL);
  261.  
  262.  
  263.    if ( tprx->f_name != NULL )
  264.       free(tprx->f_name);
  265.  
  266.    ipx_cancel_ecb(tprx->tx_ecb);
  267.    free(tprx->tx_ecb);
  268.    free(tprx->tx_data);
  269.  
  270.    tprx_ClosePool(tprx);
  271.  
  272.    if ( tprx->fp != NULL )
  273.       fclose(tprx->fp);
  274.  
  275.    ipx_close_socket(tprx->socket);
  276.  
  277.    free(tprx);
  278. }
  279.  
  280. void tprx_SetAux(tprx_type tprx, int (*aux)( int msg, void *data ))
  281. {
  282.    if ( tprx_IsOk(tprx) == 0 )
  283.       return;
  284.    tprx->aux = aux;
  285.    tprx->is_aux = 1;
  286. }
  287.  
  288. void tprx_DoAux(tprx_type tprx, int msg, void *data)
  289. {
  290.    if ( tprx_IsOk(tprx) == 0 )
  291.       return;
  292.    if ( tprx->is_aux != 0 )
  293.       tprx->aux(msg, data);
  294. }
  295.  
  296. void tprx_DoPAux(tprx_type tprx, int msg)
  297. {
  298.    tprx->pdata.total       = tprx->f_len;
  299.    tprx->pdata.curr        = tprx->f_pos;
  300.    tprx->pdata.crc         = tprx->f_crc;
  301.    tprx->pdata.path        = tprx->f_name;
  302.    tprx->pdata.file_start  = tprx->f_start;
  303.    tprx_DoAux(tprx, msg, (void *)&(tprx->pdata));
  304. }
  305.  
  306. void tprx_InitPool(tprx_type tprx, int b_curr_cnt)
  307. {
  308.    int i;
  309.    tprx->b_curr_cnt = b_curr_cnt;
  310.    tprx->b_in_cnt = 0;
  311.    tprx->b_is_any_present = 0;
  312.    for( i = 0; i < tprx->b_cnt; i++ )
  313.       tprx->b_is_present[i] = 0;
  314. }
  315.  
  316. void tprx_CopyMemoryToPool(tprx_type tprx, int no, void *adr, size_t len)
  317. {
  318.    assert(no < tprx->b_curr_cnt);
  319.    if ( tprx->b_is_present[no] == 0 )
  320.    {
  321.       memcpy(tprx->b_pool_ptr+no*tprx->b_len, adr, len);
  322.       tprx->b_in_cnt++;
  323.       tprx->b_is_present[no] = 1;
  324.       tprx->b_is_any_present = 1;
  325.    }
  326. }
  327.  
  328. void tprx_MakeMissedList(tprx_type tprx)
  329. {
  330.    int i;
  331.    int missed = 0;
  332.    for( i = 0; i < tprx->b_curr_cnt; i++ )
  333.    {
  334.       if ( tprx->b_is_present[i] == 0 )
  335.       {
  336.          tprx->b_missed_list[missed++] = (short)i;
  337.       }
  338.    }
  339.    tprx->b_missed_cnt = missed;
  340.    assert(missed == tprx->b_curr_cnt-tprx->b_in_cnt);
  341. }
  342.  
  343.  
  344. void tprx_SetFileName(tprx_type tprx, char *path)
  345. {
  346.    if ( tprx->fp != NULL )
  347.       fclose(tprx->fp);
  348.    tprx->fp = NULL;
  349.    tprx->f_exist = 0;
  350.  
  351.    if ( tprx->f_name != NULL )
  352.       free(tprx->f_name);
  353.    tprx->f_name = (char *)malloc(strlen(path)+1);
  354.    if ( tprx->f_name == NULL )
  355.       return;
  356.  
  357.    strcpy(tprx->f_name, path);
  358.    strupr(tprx->f_name);
  359.  
  360.    if ( (tprx->flags & TP_FLAG_IS_DIR) == 0 )
  361.    {
  362.       FILE *fp;
  363.       tprx->f_exist = 0;
  364.       fp = fopen(tprx->f_name, "r");
  365.       if ( fp != NULL )
  366.       {
  367.          tprx->f_exist = 1;
  368.          fclose(fp);
  369.       }
  370.    }
  371. }
  372.  
  373. void tprx_OpenFile(tprx_type tprx)
  374. {
  375.    static char drive[_MAX_DRIVE];
  376.    static char dirs[_MAX_DIR];
  377.    static char fname[_MAX_FNAME+_MAX_EXT];
  378.    static char ext[_MAX_EXT];
  379.    static char npath[_MAX_PATH];
  380.  
  381.    tprx->f_is_write_data = 0;
  382.    tprx->f_pos = 0UL;
  383.    tprx->f_crc = 0L;
  384.    tprx->f_start = 0L;
  385.  
  386.    if ( (tprx->flags & TP_FLAG_IS_TEST_MODE) == 0 )
  387.    {
  388.       char *cwd;
  389.  
  390.       tprx->fp = NULL;
  391.  
  392.       if ( (tprx->flags & TP_FLAG_IS_DIR) != 0 )
  393.       {
  394.          /* remember current path */
  395.          cwd = c_getcwd();
  396.          if ( cwd == NULL )
  397.          {
  398.             printf("can not get current working directory\n");
  399.             return;
  400.          }
  401.  
  402.          /* create directory */
  403.          if ( c_create_path(tprx->f_name) != 0 )
  404.          {
  405.             printf("can not create directory '%s'\n", tprx->f_name);
  406.             return;
  407.          }
  408.  
  409.          /* restore directory */
  410.          if ( c_set_path(cwd) != 0 )
  411.          {
  412.             printf("can not change to path '%s'\n", cwd);
  413.             return;
  414.          }
  415.       }
  416.       else
  417.       {
  418.  
  419.          /* in the next few lines, the current dir will be stored */
  420.          /* and restored... this is probably useless, because */
  421.          /* the directory is already created by the lines above */
  422.          /* But: It does not slow down the transfer process */
  423.  
  424.          _splitpath( tprx->f_name, drive, dirs, fname, ext );
  425.          /* strcpy(npath, drive); */
  426.          strcpy(npath, "");
  427.          strcat(npath, dirs);
  428.          strcat(fname, ext);
  429.  
  430.          /* create the path, if it does not exist directory */
  431.          cwd = c_getcwd();
  432.          if ( cwd == NULL )
  433.          {
  434.             printf("can not get current working directory\n");
  435.             return;
  436.          }
  437.          /* printf("cwd: %s\n", cwd); */
  438.          if ( c_create_path(npath) != 0 )
  439.          {
  440.             printf("can not create path '%s'\n", npath);
  441.             return;
  442.          }
  443.          /* printf("destpath: %s\n", npath); */
  444.          if ( c_set_path(cwd) != 0 )
  445.          {
  446.             printf("can not change to path '%s'\n", cwd);
  447.             return;
  448.          }
  449.  
  450.          /* create the file */
  451.          tprx->fp = fopen(tprx->f_name, "wb");
  452.          if ( tprx->fp == NULL )
  453.          {
  454.             printf("can not create '%s'\n", tprx->f_name);
  455.          }
  456.       }
  457.    }
  458.    else
  459.    {
  460.       printf("test mode: file/dir '%s' is not written to disk.\n", tprx->f_name);
  461.    }
  462.    tprx->f_start = clock();
  463. }
  464.  
  465. void tprx_Error(tprx_type tprx, char *s)
  466. {
  467.    fprintf(stderr, "\n");
  468.    fprintf(stderr, TPRX_ID_STR "%s\n", s);
  469.    tprx->is_ended = 1;
  470.    tprx_SetState(tprx, tprx_state_none);
  471.  
  472.    if ( tprx->is_adr_known != 0 )
  473.    {
  474.       clock_t c1 = clock() + CLOCKS_PER_SEC;
  475.       long cnt = 4L;
  476.       while ( clock() < c1 && cnt > 0L )
  477.       {
  478.          clock_t c2;
  479.          ipx_dispatch();
  480.          if ( tprx->tx_ecb->inuse == 0 )
  481.          {
  482.             tp_set_blk_id(tprx->tx_data, TP_ID_ERROR);
  483.             tp_set_blk_ver(tprx->tx_data, TP_VERSION);
  484.             strcpy(tp_get_blk_data_adr(tprx->tx_data), s);
  485.  
  486.             ipx_fill_send_ecb(
  487.                tprx->tx_ecb,
  488.                ipx_get_header(&(tprx->adr), tprx->socket, tprx->socket),
  489.                tprx->tx_data,
  490.                tprx->b_len+TP_BLK_INFO_SIZE);
  491.  
  492.             ipx_send_ecb(tprx->tx_ecb);
  493.             cnt--;
  494.          }
  495.          c2 = clock() + CLOCKS_PER_SEC/8;
  496.          while ( clock() < c2  )
  497.             ;
  498.       }
  499.    }
  500. }
  501.  
  502. size_t tprx_GetWriteSize(tprx_type tprx)
  503. {
  504.    size_t elen;
  505.  
  506.    if ( tprx->f_len-tprx->f_pos >= (long)tprx->b_pool_size )
  507.       elen = tprx->b_pool_size;
  508.    else
  509.       elen = (size_t)(tprx->f_len-tprx->f_pos);
  510.  
  511.    return elen;
  512. }
  513.  
  514. int tprx_Write(tprx_type tprx)
  515. {
  516.    size_t len, i;
  517.    len = tprx_GetWriteSize(tprx);
  518.  
  519.    if ( (tprx->flags & TP_FLAG_IS_DISABLE_CRC) == 0 )
  520.    {
  521.       if ( (tprx->flags & TP_FLAG_IS_CRC32) == 0 )
  522.       {
  523.          for( i = 0; i < len; i += 1024 )
  524.          {
  525.             ipx_dispatch();
  526.             tprx->f_crc = (unsigned long)crc16((unsigned short)tprx->f_crc,
  527.                (unsigned char *)tprx->b_pool_ptr+(size_t)i,
  528.                (len > i+1024) ? 1024 : len-i);
  529.          }
  530.       }
  531.       else
  532.       {
  533.          for( i = 0; i < len; i += 1024 )
  534.          {
  535.             ipx_dispatch();
  536.             tprx->f_crc = crc32(tprx->f_crc,
  537.                (unsigned char *)tprx->b_pool_ptr+(size_t)i,
  538.                (len > i+1024) ? 1024 : len-i);
  539.          }
  540.       }
  541.       if ( tprx->f_crc != tprx->f_remote_crc )
  542.       {
  543.          tprx_Error(tprx, "crc error");
  544.          return 0;
  545.       }
  546.       /*
  547.       tprx->f_crc = crc32(tprx->f_crc,
  548.          (unsigned char *)tprx->b_pool_ptr, len);
  549.       */
  550.    }
  551.    if ( (tprx->flags & TP_FLAG_IS_TEST_MODE) == 0 )
  552.    {
  553.       if ( tprx->f_is_write_data != 0 && tprx->fp != NULL )
  554.       {
  555.          if ( len > 0 )
  556.          {
  557.             if ( fwrite(tprx->b_pool_ptr, len, 1, tprx->fp) != 1 )
  558.             {
  559.                tprx_Error(tprx, "write error");
  560.                return 0;
  561.             }
  562.          }
  563.       }
  564.    }
  565.    tprx->f_pos += (long)len;
  566.    tprx->f_is_write_data = 0;
  567.    return 1;
  568. }
  569.  
  570. void tprx_CloseFile(tprx_type tprx)
  571. {
  572.    if ( (tprx->flags & TP_FLAG_IS_TEST_MODE) == 0 )
  573.    {
  574.       if ( tprx->fp != NULL )
  575.       {
  576.          int handle;
  577.          fclose(tprx->fp);
  578.          tprx->fp = NULL;
  579.          _dos_setfileattr( tprx->f_name, (tprx->f_attr) );
  580.          _dos_open( tprx->f_name, _O_RDONLY, &handle );
  581.          _dos_setftime( handle, tprx->f_date, tprx->f_time );
  582.          _dos_close( handle );
  583.       }
  584.    }
  585. }
  586.  
  587. int tprx_ListenECB(tprx_type tprx, int i)
  588. {
  589.    if ( tprx->rx_ecb[i]->inuse != 0 )
  590.    {
  591.       return 1;
  592.    }
  593.    if ( ipx_fill_receive_ecb(
  594.       tprx->rx_ecb[i],
  595.       tprx->socket,
  596.       tprx->rx_data[i],
  597.       tprx->b_len+TP_BLK_INFO_SIZE) == NULL )
  598.    {
  599.       tprx_Error(tprx, "cannot fill receive ecb");
  600.       return 0;
  601.    }
  602.    if ( ipx_listen_ecb(tprx->rx_ecb[i]) == 0 )
  603.    {
  604.       tprx_Error(tprx, "cannot listen to ecb");
  605.       return 0;
  606.    }
  607.    return 1;
  608. }
  609.  
  610. int tprx_ListenAll(tprx_type tprx)
  611. {
  612.    int i;
  613.    for( i = 0; i < tprx->rx_cnt; i++ )
  614.    {
  615.       if ( tprx_ListenECB(tprx, i) == 0 )
  616.          return 0;
  617.    }
  618.    return 1;
  619. }
  620.  
  621. int tprx_ListenExcept(tprx_type tprx, int id1, int id2)
  622. {
  623.    int i;
  624.    for( i = 0; i < tprx->rx_cnt; i++ )
  625.    {
  626.       if ( tprx->rx_ecb[i]->inuse == 0 )
  627.       {
  628.          if ( tprx->rx_ecb[i]->cc == 0 )
  629.          {
  630.             if ( tp_ecb_get_id(tprx->rx_ecb[i]) == TP_ID_ERROR )
  631.             {
  632.                static char s[80];
  633.                sprintf(s, "remote error: '%s'", tp_ecb_get_data_adr(tprx->rx_ecb[i]));
  634.                tprx_Error(tprx, s);
  635.                return 0;
  636.             }
  637.             if (tp_ecb_get_id(tprx->rx_ecb[i]) != id1 &&
  638.                 tp_ecb_get_id(tprx->rx_ecb[i]) != id2)
  639.             {
  640.                if ( tprx_ListenECB(tprx, i) == 0 )
  641.                   return 0;
  642.             }
  643.          }
  644.          else
  645.          {
  646.             printf( TPRX_ID_STR "receiver warning: %s\n", 
  647.                ipx_get_ecb_cc_string(tprx->rx_ecb[i]));
  648.             if ( tprx_ListenECB(tprx, i) == 0 )
  649.                return 0;
  650.          }
  651.       }
  652.    }
  653.    return 1;
  654. }
  655.  
  656.  
  657. /*
  658.    search for a received block with identifier id
  659.    return index to rx_ecb array or -1, if id not found
  660. */
  661. int tprx_SearchId(tprx_type tprx, short id)
  662. {
  663.    int i;
  664.    assert(tprx != NULL);
  665.    for( i = 0; i < tprx->rx_cnt; i++ )
  666.    {
  667.       if ( tprx->rx_ecb[i]->inuse == 0 )
  668.       {
  669.          if ( tprx->rx_ecb[i]->cc != 0 )
  670.          {
  671.             tprx_Error(tprx, ipx_get_ecb_cc_string(tprx->rx_ecb[i]));
  672.             tprx_ListenECB(tprx, i);
  673.          }
  674.          else if (tp_ecb_get_id(tprx->rx_ecb[i]) == id)
  675.          {
  676.             if ( tp_ecb_get_ver(tprx->rx_ecb[i]) != TP_VERSION )
  677.             {
  678.                tprx_Error(tprx, "wrong version");
  679.             }
  680.             else
  681.             {
  682.                return i;
  683.             }
  684.          }
  685.       }
  686.    }
  687.    return -1;
  688. }
  689.  
  690.  
  691.  
  692. int tprx_ListenAndSearch(tprx_type tprx, int id)
  693. {
  694.    tprx_ListenExcept(tprx, id, TP_ID_NONE);
  695.    return tprx_SearchId(tprx, id);
  696. }
  697.  
  698. void tprx_SendECB(tprx_type tprx)
  699. {
  700.    tp_set_blk_ver(tprx->tx_data, TP_VERSION);
  701.  
  702.    ipx_fill_send_ecb(
  703.       tprx->tx_ecb,
  704.       ipx_get_header(&(tprx->adr), tprx->socket, tprx->socket),
  705.       tprx->tx_data,
  706.       tprx->b_len+TP_BLK_INFO_SIZE);
  707.  
  708.    if ( ipx_send_ecb(tprx->tx_ecb) == 0 )
  709.    {
  710.       static char s[80];
  711.       sprintf(s, "cannot send msg %d", tp_get_blk_id(tprx->tx_data) );
  712.       tprx_Error(tprx, s);
  713.    }
  714. }
  715.  
  716. void tprx_WaitSend(tprx_type tprx,
  717.    void (*next_state)(tprx_type tprx),
  718.    void (*repeated_state)(tprx_type tprx),
  719.    clock_t delay)
  720. {
  721.    if ( tprx->tx_ecb->inuse == 0 )
  722.    {
  723.       if ( tprx->tx_ecb->cc != 0 )
  724.       {
  725.          tprx_Error(tprx, ipx_get_ecb_cc_string(tprx->tx_ecb));
  726.       }
  727.       else
  728.       {
  729.          tprx->clock_dest = clock()+delay;
  730.          tprx_SetRepeatedState(tprx, repeated_state);
  731.          tprx_SetState(tprx, next_state);
  732.       }
  733.    }
  734. }
  735.  
  736. int tprx_CheckTime(tprx_type tprx)
  737. {
  738.    if ( tprx->clock_dest < clock() )
  739.    {
  740.       tprx_SetState(tprx, tprx_GetRepeatedState(tprx));
  741.       return 0;
  742.    }
  743.    return 1;
  744. }
  745.  
  746. int tprx_Dispatch(tprx_type tprx)
  747. {
  748.    ipx_dispatch();
  749.    if( tprx->is_ended != 0 )
  750.       return 1;
  751.    tprx->state_fn(tprx);
  752.    if ( tprx->state_fn != tprx_state_user_check )
  753.    {
  754.       if ( kbhit() != 0 )
  755.       {
  756.          if ( getch() == 27 )
  757.          {
  758.             tprx_Error(tprx, "user break");
  759.          }
  760.       }
  761.    }
  762.    return tprx->is_ended;
  763. }
  764.  
  765.  
  766. /* - - - - - state functions - - - - - - - - - - - - - - - - - - - - - - - */
  767.  
  768. void tprx_state_none(tprx_type tprx)
  769. {
  770.    int pos;
  771.  
  772.    pos = tprx_ListenAndSearch(tprx, TP_ID_REQUEST);
  773.    if ( pos >= 0 )
  774.    {
  775.       tp_request request;
  776.       request = (tp_request)tp_ecb_get_data_adr(tprx->rx_ecb[pos]);
  777.       tprx->adr = request->adr;
  778.       tprx->is_adr_known = 1;
  779.       tprx->f_len = request->file_size;
  780.       tprx->flags = request->flags;
  781.       tprx->f_attr = request->attr;
  782.       tprx->f_time = request->time;
  783.       tprx->f_date = request->date;
  784.       tprx_SetFileName(tprx,
  785.          tp_ecb_get_data_adr(tprx->rx_ecb[pos])+sizeof(tp_request_struct));
  786.       tprx_ListenECB(tprx, pos);
  787.       tprx_SetState(tprx, tprx_state_gen_ack_request);
  788.       if ( tprx->f_exist != 0 && (tprx->flags&TP_FLAG_IS_NO_USER_CHECK) == 0 )
  789.       {
  790.          printf("local file '%s' exists, overwrite (y,n,a)? ",
  791.             tprx->f_name);
  792.          fflush(stdout);
  793.       }
  794.    }
  795. }
  796.  
  797. void tprx_state_gen_ack_request(tprx_type tprx)
  798. {
  799.    tp_ack_request ack_request;
  800.  
  801.    tp_debug_out("tprx_state_gen_ack_request");
  802.  
  803.    ack_request = (tp_ack_request)tp_get_blk_data_adr(tprx->tx_data);
  804.    ack_request->adr = *ipx_get_local_net_number();
  805.    ack_request->exist = tprx->f_exist;
  806.  
  807.    tp_set_blk_id(tprx->tx_data, TP_ID_ACK_REQUEST);
  808.  
  809.    tprx_SendECB(tprx);
  810.  
  811.    tprx_SetState(tprx, tprx_state_chk_ack_request);
  812. }
  813.  
  814. void tprx_state_chk_ack_request(tprx_type tprx)
  815. {
  816.    tp_debug_out("tprx_state_chk_ack_request");
  817.  
  818.    if ( tprx->f_exist != 0 && (tprx->flags&TP_FLAG_IS_NO_USER_CHECK) == 0 )
  819.    {
  820.       tprx_WaitSend(tprx,
  821.          tprx_state_user_check,
  822.          tprx_state_gen_ack_request,
  823.          tprx->large_delay);
  824.    }
  825.    else
  826.    {
  827.       tprx_WaitSend(tprx,
  828.          tprx_state_wait_file_start,
  829.          tprx_state_gen_ack_request,
  830.          tprx->large_delay);
  831.    }
  832. }
  833.  
  834. void tprx_state_user_check(tprx_type tprx)
  835. {
  836.    int pos;
  837.    if ( tprx_CheckTime(tprx) == 0 )
  838.       return;
  839.    tprx->f_is_skip = 0;
  840.    if ( kbhit() != 0 )
  841.    {
  842.       int c = getch();
  843.       switch(c)
  844.       {
  845.          case 'n':
  846.          case 'N':
  847.             printf("%c\n", c);
  848.             tprx->f_is_skip = 1;
  849.             tprx_SetState(tprx, tprx_state_gen_file_start);
  850.             return;
  851.          case 'a':
  852.          case 'A':
  853.             printf("%c\n", c);
  854.             tprx_SetFlag(tprx, TP_FLAG_IS_NO_USER_CHECK);
  855.             tprx_DoPAux(tprx, TP_MSG_PSTART);
  856.             tprx_SetState(tprx, tprx_state_gen_file_start);
  857.             return;
  858.          case 'y':
  859.          case 'Y':
  860.          case 'j':
  861.          case 'J':
  862.             printf("%c\n", c);
  863.             tprx_DoPAux(tprx, TP_MSG_PSTART);
  864.             tprx_SetState(tprx, tprx_state_gen_file_start);
  865.             return;
  866.          case 27:
  867.             tprx_Error(tprx, "user escape");
  868.             return;
  869.  
  870.       }
  871.    }
  872.    tprx_ListenExcept(tprx, TP_ID_FILE_START, TP_ID_FILE_END);
  873.    pos = tprx_SearchId(tprx, TP_ID_FILE_START);
  874.    if ( pos >= 0 )
  875.    {
  876.       printf("y/a\n");
  877.       /* tprx_ListenECB(tprx, pos); */
  878.       tprx_DoPAux(tprx, TP_MSG_PSTART);
  879.       tprx_SetState(tprx, tprx_state_wait_file_start);
  880.       return;
  881.    }
  882.    pos = tprx_SearchId(tprx, TP_ID_FILE_END);
  883.    if ( pos >= 0 )
  884.    {
  885.       printf("n\n");
  886.       tprx_SetState(tprx, tprx_state_gen_ack_file_end);
  887.       tprx_ListenECB(tprx, pos);
  888.       return;
  889.    }
  890.  
  891.  
  892. }
  893.  
  894. void tprx_state_gen_file_start(tprx_type tprx)
  895. {
  896.    tp_file_start file_start;
  897.  
  898.    tp_debug_out("tprx_state_gen_file_start");
  899.  
  900.    file_start = (tp_file_start)tp_get_blk_data_adr(tprx->tx_data);
  901.    file_start->is_skip_file = tprx->f_is_skip;
  902.    file_start->flags = tprx->flags;
  903.  
  904.    tp_set_blk_id(tprx->tx_data, TP_ID_FILE_START);
  905.    tprx_SendECB(tprx);
  906.  
  907.    tprx_SetState(tprx, tprx_state_chk_file_start);
  908. }
  909.  
  910. void tprx_state_chk_file_start(tprx_type tprx)
  911. {
  912.    tp_debug_out("tprx_state_chk_file_start");
  913.  
  914.    tprx_WaitSend(tprx,
  915.       tprx_state_wait_file_start,
  916.       tprx_state_gen_file_start,
  917.       tprx->small_delay);
  918. }
  919.  
  920. void tprx_state_wait_file_start(tprx_type tprx)
  921. {
  922.    int pos;
  923.  
  924.    /* tp_debug_out("tprx_state_wait_file_start"); */
  925.  
  926.    tprx_ListenExcept(tprx, TP_ID_FILE_START, TP_ID_FILE_END);
  927.    pos = tprx_SearchId(tprx, TP_ID_FILE_START);
  928.    if ( pos >= 0 )
  929.    {
  930.       tp_file_start file_start;
  931.       file_start = (tp_file_start)tp_ecb_get_data_adr(tprx->rx_ecb[pos]);
  932.       if ( file_start->is_skip_file != 0 )
  933.       {
  934.          tprx_SetState(tprx, tprx_state_none);
  935.       }
  936.       else
  937.       {
  938.          tprx_OpenFile(tprx);
  939.          tprx_DoPAux(tprx, TP_MSG_PSTART);
  940.          tprx_SetState(tprx, tprx_state_gen_ack_file_start);
  941.          tprx->f_start = clock();
  942.       }
  943.       tprx_ListenECB(tprx, pos);
  944.       return;
  945.    }
  946.    pos = tprx_SearchId(tprx, TP_ID_FILE_END);
  947.    if ( pos >= 0 )
  948.    {
  949.       tprx_SetState(tprx, tprx_state_gen_ack_file_end);
  950.       tprx_ListenECB(tprx, pos);
  951.       return;
  952.    }
  953.  
  954.    /* user may jump here... so time check is at the end */
  955.    if ( tprx_CheckTime(tprx) == 0 )
  956.       return;
  957.  
  958. }
  959.  
  960. void tprx_state_gen_ack_file_start(tprx_type tprx)
  961. {
  962.    tp_debug_out("tprx_state_gen_ack_file_start");
  963.  
  964.    tp_set_blk_id(tprx->tx_data, TP_ID_ACK_FILE_START);
  965.    tprx_SendECB(tprx);
  966.    tprx_SetState(tprx, tprx_state_chk_ack_file_start);
  967. }
  968.  
  969. void tprx_state_chk_ack_file_start(tprx_type tprx)
  970. {
  971.    tp_debug_out("tprx_state_chk_ack_file_start");
  972.  
  973.    tprx_WaitSend(tprx,
  974.       tprx_state_wait_block_start,
  975.       tprx_state_gen_ack_file_start,
  976.       tprx->large_delay);
  977. }
  978.  
  979. void tprx_state_wait_block_start(tprx_type tprx)
  980. {
  981.    int pos;
  982.  
  983.    tp_debug_out("tprx_state_wait_block_start");
  984.  
  985.    if ( tprx_CheckTime(tprx) == 0 )
  986.       return;
  987.    tprx_ListenExcept(tprx, TP_ID_BLOCK_START, TP_ID_FILE_END);
  988.    pos = tprx_SearchId(tprx, TP_ID_BLOCK_START);
  989.    if ( pos >= 0 )
  990.    {
  991.       tp_block_start block_start;
  992.       block_start = (tp_block_start)tp_ecb_get_data_adr(tprx->rx_ecb[pos]);
  993.       tprx_DoPAux(tprx, TP_MSG_PDATA);
  994.       tprx_InitPool(tprx, (int)block_start->cnt);
  995.       tprx_SetState(tprx, tprx_state_gen_ack_block_start);
  996.       tprx_ListenECB(tprx, pos);
  997.    }
  998.    pos = tprx_SearchId(tprx, TP_ID_FILE_END);
  999.    if ( pos >= 0 )
  1000.    {
  1001.       if ( tprx->f_is_write_data != 0 )
  1002.          tprx_Write(tprx);
  1003.       tprx_DoPAux(tprx, TP_MSG_PDATA);
  1004.       tprx_DoPAux(tprx, TP_MSG_PEND);
  1005.       tprx_CloseFile(tprx);
  1006.       tprx_SetState(tprx, tprx_state_gen_ack_file_end);
  1007.       tprx_ListenECB(tprx, pos);
  1008.    }
  1009. }
  1010.  
  1011. void tprx_state_gen_ack_block_start(tprx_type tprx)
  1012. {
  1013.    tp_debug_out("tprx_state_gen_ack_block_start");
  1014.  
  1015.    tp_set_blk_id(tprx->tx_data, TP_ID_ACK_BLOCK_START);
  1016.    tprx_SendECB(tprx);
  1017.    tprx_SetState(tprx, tprx_state_chk_ack_block_start);
  1018. }
  1019.  
  1020. void tprx_state_chk_ack_block_start(tprx_type tprx)
  1021. {
  1022.    tp_debug_out("tprx_state_chk_ack_block_start");
  1023.  
  1024.    tprx_WaitSend(tprx,
  1025.       tprx_state_wait_data,
  1026.       tprx_state_gen_ack_block_start,
  1027.       tprx->small_delay);
  1028. }
  1029.  
  1030. void tprx_state_wait_data(tprx_type tprx)
  1031. {
  1032.    int pos;
  1033.  
  1034.    /* tp_debug_out("tprx_state_wait_data"); */
  1035.  
  1036.    if ( tprx->f_is_write_data != 0 )
  1037.       tprx_Write(tprx);
  1038.    if ( tprx_IsAnyPresent(tprx) == 0 )
  1039.       if ( tprx_CheckTime(tprx) == 0 )
  1040.          return;
  1041.    /* tprx_ListenExcept(tprx, TP_ID_DATA, TP_ID_BLOCK_END); */
  1042.    pos = tprx_SearchId(tprx, TP_ID_ERROR);
  1043.    if ( pos >= 0 )
  1044.    {
  1045.       static char s[80];
  1046.       sprintf(s, "remote error: '%s'", tp_ecb_get_data_adr(tprx->rx_ecb[pos]));
  1047.       tprx_Error(tprx, s);
  1048.       return;
  1049.    }
  1050.  
  1051.    pos = tprx_SearchId(tprx, TP_ID_DATA);
  1052.    if ( pos >= 0 )
  1053.    {
  1054.       tp_data d;
  1055.       d = (tp_data)tp_ecb_get_data_adr(tprx->rx_ecb[pos]);
  1056.       tprx_CopyMemoryToPool(tprx,
  1057.          d->no,
  1058.          tp_ecb_get_data_adr(tprx->rx_ecb[pos])+sizeof(tp_data_struct),
  1059.          (size_t)(d->len));
  1060.       /*
  1061.       printf("(%d,%d/%d)", (int)d->no, tprx->b_in_cnt, tprx->b_curr_cnt);
  1062.       */
  1063.       tprx_ListenECB(tprx, pos);
  1064.    }
  1065.    else
  1066.    {
  1067.       pos = tprx_SearchId(tprx, TP_ID_BLOCK_END);
  1068.       if ( pos >= 0 )
  1069.       {
  1070.          /*
  1071.          printf("TP_ID_BLOCK_END at pos %d found, missed cnt: %d\n",
  1072.             pos, tprx->b_curr_cnt-tprx->b_in_cnt);
  1073.          */
  1074.          tprx_ListenECB(tprx, pos);
  1075.          if ( tprx->b_curr_cnt == tprx->b_in_cnt )
  1076.          {
  1077.             tp_block_end block_end;
  1078.             block_end = (tp_block_end)tp_ecb_get_data_adr(tprx->rx_ecb[pos]);
  1079.             tprx->f_remote_crc = block_end->crc;
  1080.             tprx->f_is_write_data = 1;
  1081.             tprx_SetState(tprx, tprx_state_gen_ack_block_end);
  1082.          }
  1083.          else
  1084.          {
  1085.             tprx_MakeMissedList(tprx);
  1086.             tprx_SetState(tprx, tprx_state_gen_missed_blocks);
  1087.          }
  1088.       }
  1089.    }
  1090. }
  1091.  
  1092. void tprx_state_gen_missed_blocks(tprx_type tprx)
  1093. {
  1094.    tp_missed_blocks missed_blocks;
  1095.  
  1096.    tp_debug_out("tprx_state_gen_missed_blocks");
  1097.    /* printf("missed: %d\n", (int)tprx->b_missed_cnt); */
  1098.  
  1099.    missed_blocks = (tp_missed_blocks)tp_get_blk_data_adr(tprx->tx_data);
  1100.    missed_blocks->cnt = tprx->b_missed_cnt;
  1101.    memcpy( tp_get_blk_data_adr(tprx->tx_data)+sizeof(tp_missed_blocks_struct),
  1102.       tprx->b_missed_list, tprx->b_missed_cnt*sizeof(short));
  1103.  
  1104.    tp_set_blk_id(tprx->tx_data, TP_ID_MISSED_BLOCKS);
  1105.  
  1106.    tprx_SendECB(tprx);
  1107.  
  1108.    tprx_SetState(tprx, tprx_state_chk_missed_blocks);
  1109. }
  1110.  
  1111. void tprx_state_chk_missed_blocks(tprx_type tprx)
  1112. {
  1113.    tp_debug_out("tprx_state_chk_missed_blocks");
  1114.  
  1115.    tprx_WaitSend(tprx,
  1116.       tprx_state_wait_data,
  1117.       tprx_state_gen_missed_blocks,
  1118.       tprx->small_delay);
  1119. }
  1120.  
  1121. void tprx_state_gen_ack_block_end(tprx_type tprx)
  1122. {
  1123.    tp_debug_out("tprx_state_gen_ack_block_end");
  1124.  
  1125.    tp_set_blk_id(tprx->tx_data, TP_ID_ACK_BLOCK_END);
  1126.    tprx_SendECB(tprx);
  1127.    tprx_SetState(tprx, tprx_state_chk_ack_block_end);
  1128. }
  1129.  
  1130. void tprx_state_chk_ack_block_end(tprx_type tprx)
  1131. {
  1132.    tp_debug_out("tprx_state_chk_ack_block_end");
  1133.  
  1134.    tprx_WaitSend(tprx,
  1135.       tprx_state_wait_block_start,
  1136.       tprx_state_gen_ack_block_end,
  1137.       tprx->small_delay);
  1138. }
  1139.  
  1140. void tprx_state_gen_ack_file_end(tprx_type tprx)
  1141. {
  1142.    tp_debug_out("tprx_state_gen_ack_file_end");
  1143.  
  1144.    tp_set_blk_id(tprx->tx_data, TP_ID_ACK_FILE_END);
  1145.    tprx_SendECB(tprx);
  1146.    tprx_SetState(tprx, tprx_state_chk_ack_file_end);
  1147. }
  1148.  
  1149. void tprx_state_chk_ack_file_end(tprx_type tprx)
  1150. {
  1151.    tp_debug_out("tprx_state_chk_ack_file_end");
  1152.  
  1153.    tprx_WaitSend(tprx,
  1154.       tprx_state_none2,
  1155.       tprx_state_gen_ack_file_end,
  1156.       tprx->large_delay);
  1157. }
  1158.  
  1159. void tprx_state_none2(tprx_type tprx)
  1160. {
  1161.    int pos;
  1162.    /* tp_debug_out("tprx_state_none2"); */
  1163.    if ( tprx_CheckTime(tprx) == 0 )
  1164.       return;
  1165.    pos = tprx_ListenAndSearch(tprx, TP_ID_REQUEST);
  1166.    if ( pos >= 0 )
  1167.    {
  1168.       tprx_SetState(tprx, tprx_state_none);
  1169.    }
  1170. }
  1171.