home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / bin / p205.zip / exesrc / callback.c < prev    next >
C/C++ Source or Header  |  1994-12-18  |  26KB  |  1,003 lines

  1. /*****************************************************************************/
  2. /*           Copyright (c) 1994 by Jyrki Salmi <jytasa@jyu.fi>             */
  3. /*        You may modify, recompile and distribute this file freely.         */
  4. /*****************************************************************************/
  5.  
  6. /*
  7.    Callback functions called by P.DLL
  8. */
  9.  
  10. #include <stdio.h>
  11. #define INCL_DOSPROCESS
  12. #include <os2.h>
  13. #include <stdlib.h>
  14. #include <stdarg.h>
  15. #include <string.h>
  16. #include <io.h>
  17. #include <fcntl.h>
  18. #include <sys\types.h>
  19. #include <sys\stat.h>
  20. #include <sys\utime.h>
  21. #include <share.h>
  22. #include <time.h>
  23. #include <ctype.h>
  24. #include <errno.h>
  25. #include "typedefs.h"
  26. #include "p.h"
  27. #include "callback.h"
  28. #include "common.h"
  29. #include "brw.h"
  30. #include "error.h"
  31. #include "global.h"
  32. #include "modules.h"
  33.  
  34. U8 *z_header[] = {
  35.  
  36.   "TIMEOUT",
  37.   "ZRQINIT",
  38.   "ZRINIT",
  39.   "ZSINIT",
  40.   "ZACK",
  41.   "ZFILE",
  42.   "ZSKIP",
  43.   "ZNAK",
  44.   "ZABORT",
  45.   "ZFIN",
  46.   "ZRPOS",
  47.   "ZDATA",
  48.   "ZEOF",
  49.   "ZFERR",
  50.   "ZCRC",
  51.   "ZCHALLENGE",
  52.   "ZCOMPL",
  53.   "ZCAN",
  54.   "ZFREECNT",
  55.   "ZCOMMAND",
  56.   "ZSTDERR"
  57. };
  58.  
  59. U8 *z_frame_end[] = {
  60.  
  61.   "TIMEOUT",
  62.   "ZCRCE",
  63.   "ZCRCG",
  64.   "ZCRCQ",
  65.   "ZCRCW",
  66.   "ZERROR",
  67.   "ZCAN"
  68. };
  69.  
  70. /* Makes an array of va_list */
  71.  
  72. void make_arg_list(U32 *arg_list, va_list arg_ptr, U32 cnt) {
  73.  
  74.   U32 idx;
  75.  
  76.   for (idx = 0; idx < cnt; idx++)
  77.     arg_list[idx] = va_arg(arg_ptr, int);
  78. }
  79.  
  80. BOOLEAN _System status_func(U32 type, ...) {
  81.  
  82.   static U32 checking_method = 0;
  83.   static U32 receiver_flags = 0;
  84.   static S32 receiver_window_size = -1;
  85.   va_list arg_ptr;
  86.   U32 arg_list[10];        /* No more than 10 parameters for status */
  87.                 /* message possible */
  88.  
  89.   /* Make an array from arg_ptr */
  90.   va_start(arg_ptr, type);
  91.   make_arg_list(arg_list, arg_ptr, 10);
  92.   va_end(arg_ptr);
  93.  
  94.   switch (type) {
  95.   case PS_ERROR:
  96.     if (is_os2_error(arg_list[0])) {
  97.       os2_error(arg_list[0],         /* Error num */
  98.         arg_list[1],         /* Return code */
  99.         arg_list[2],         /* Module */
  100.         arg_list[3],         /* Line num */
  101.         (U8 *)arg_list[4]);     /* Optional argument */
  102.     } else if (is_tcpip_error(arg_list[0])) {
  103.       tcpip_error(arg_list[0],         /* Error num */
  104.           arg_list[1],         /* Return code */
  105.           arg_list[2],         /* Module */
  106.           arg_list[3],         /* Line num */
  107.           (U8 *)arg_list[4]); /* Optional argument */
  108.     }
  109.     break;
  110.  
  111.   case PS_CARRIER_LOST:
  112.     carrier_lost = 1;
  113.     msg(MSG_LF, "Carrier lost");
  114.     break;
  115.  
  116.   case PS_TIMEOUT:
  117.     msg(MSG_LF, "Timeout (%lu secs)",
  118.     arg_list[0]);
  119.     break;
  120.  
  121.   case PS_TRANSFER_DONE:
  122.     msg(MSG_LF, "Transfer done!");
  123.     break;
  124.  
  125.   case PS_PROGRESS:
  126.     msg(MSG_CR, "%lu",
  127.     arg_list[0]);
  128.     break;
  129.  
  130.   case PS_CANNOT_SEND_BLOCK:
  131.     msg(MSG_LF, "Can't send block");
  132.     break;
  133.  
  134.   case PS_CHECKING_METHOD:
  135.     if (checking_method != arg_list[0]) { /* Has the checking method */
  136.                       /* changed since last displayed? */
  137.       checking_method = arg_list[0];
  138.       switch (checking_method) {
  139.       case CHECKING_CHECKSUM:
  140.     msg(MSG_CR | MSG_LF, "Checksum checking will be used");
  141.     break;
  142.     
  143.       case CHECKING_CRC16:
  144.     msg(MSG_CR | MSG_LF, "CRC-16 checking will be used");
  145.     break;
  146.     
  147.       case CHECKING_CRC32:
  148.       default:            /* To shut up the compiler */
  149.     msg(MSG_CR | MSG_LF, "CRC-32 checking will be used");
  150.     break;
  151.       }
  152.     }
  153.     break;
  154.  
  155.   case PS_INVALID_FILE_INFO:
  156.     msg(MSG_LF, "Got invalid file info");
  157.     break;
  158.  
  159.   case PS_NON_STD_FILE_INFO:
  160.     msg(MSG_LF, "Got non-standard file info");
  161.     break;
  162.  
  163.   case PS_XY_FALLBACK_TO_CHECKSUM:
  164.     msg(MSG_LF, "Falling back to checksum checking...");
  165.     break;
  166.  
  167.   case PS_CHECK_FAILED:
  168.     switch (arg_list[0]) {
  169.     case CHECKING_CHECKSUM:
  170.       msg(MSG_LF, "Checksum mismatch");
  171.       break;
  172.  
  173.     case CHECKING_CRC16:
  174.       msg(MSG_LF, "CRC-16 mismatch");
  175.       break;
  176.  
  177.     case CHECKING_CRC32:
  178.       msg(MSG_LF, "CRC-32 mismatch");
  179.       break;
  180.     }
  181.     break;
  182.  
  183.   case PS_REMOTE_ABORTED:
  184.     msg(MSG_LF, "Remote aborted");
  185.     break;
  186.  
  187.   case PS_G_ABORTED:
  188.     msg(MSG_LF, "Cancelling Ymodem-g transfer");
  189.     break;
  190.  
  191.   case PS_XYG_NAK:
  192.     msg(MSG_LF, "Got NAK on byte %lu",
  193.     arg_list[0]);
  194.     break;
  195.  
  196.   case PS_XYG_BLK_NUM_MISMATCH:
  197.     msg(MSG_LF, "Block numbers mismatch (%lu:%lu <> %lu:%lu)",
  198.     arg_list[0], arg_list[1],
  199.     arg_list[2], arg_list[3]);
  200.     break;
  201.  
  202.   case PS_Z_HEADER:
  203.     if (opt_headers) {
  204.       msg(MSG_LF, "%s %lu",
  205.       z_header[arg_list[0]], arg_list[1]);
  206.     }
  207.     break;
  208.  
  209.   case PS_Z_UNEXPECTED_HEADER:
  210.     msg(MSG_LF, "Unexpected %s %lu",
  211.     z_header[arg_list[0]], arg_list[1]);
  212.     break;
  213.  
  214.   case PS_Z_FRAME_END:
  215.     if (opt_frameends)
  216.       msg(MSG_LF, "%s", z_frame_end[arg_list[0]]);
  217.     break;
  218.  
  219.   case PS_Z_INVALID_FRAME_END:
  220.     msg(MSG_LF, "Invalid frame end: %s",
  221.     z_frame_end[arg_list[0]]);
  222.     break;
  223.  
  224.   case PS_Z_PHONY_ZEOF:
  225.     msg(MSG_LF, "Got phony ZEOF");
  226.     break;
  227.  
  228.   case PS_Z_RETRY_CNT_EXCEEDED:
  229.     msg(MSG_LF, "Retry count exceeded");
  230.     break;
  231.  
  232.   case PS_Z_DATA_FROM_INVALID_POS:
  233.     msg(MSG_LF, "Got data from invalid position: %lu, expected from %lu",
  234.     arg_list[0], arg_list[1]);
  235.     break;
  236.  
  237.   case PS_Z_COMMAND:
  238.     msg(MSG_LF, "Zcommand: \"%s\"", arg_list[0]);
  239.     break;
  240.  
  241.   case PS_Z_CTRL_CHAR_IGNORED:
  242.     msg(MSG_LF, "Unexpected control character ignored: %lu",
  243.     arg_list[0]);
  244.     break;
  245.  
  246.   case PS_Z_INVALID_ZDLE_SEQUENCE:
  247.     msg(MSG_LF, "Invalid ZDLE sequence received");
  248.     break;
  249.  
  250.   case PS_Z_CHECK_FAILED_FOR_HEADER:
  251.     switch (arg_list[0]) {
  252.     case CHECKING_CHECKSUM:
  253.       /* This never happens... Checksum checking isn't used for headers! */
  254.       break;
  255.  
  256.     case CHECKING_CRC16:
  257.       msg(MSG_LF, "CRC-16 mismatch for a header");
  258.       break;
  259.  
  260.     case CHECKING_CRC32:
  261.       msg(MSG_LF, "CRC-32 mismatch for a header");
  262.       break;
  263.     }
  264.     break;
  265.  
  266.   case PS_Z_INVALID_HEX_HEADER:
  267.     msg(MSG_LF, "Invalid zmodem hex header received");
  268.     break;
  269.  
  270.   case PS_Z_SUBPACKET_TOO_LONG:
  271.     msg(MSG_LF, "Too long zmodem subpacket received (> %lu)",
  272.     arg_list[0]);
  273.     break;
  274.  
  275.   case PS_Z_CRASH_RECOVERY:
  276.     msg(MSG_LF, "Crash recovery at %lu",
  277.     arg_list[0]);
  278.     break;
  279.  
  280.   case PS_Z_RECEIVER_FLAGS:
  281.     if (receiver_flags != arg_list[0]) {
  282.       if (receiver_flags != 0)    /* We have parsed zrinit */
  283.                 /* at least once before */
  284.     msg(MSG_CR | MSG_LF, "Receiver has changed its parameters");
  285.  
  286.       receiver_flags = arg_list[0];
  287.  
  288.       if (receiver_flags & RZ_FLAG_CANFDX)
  289.     msg(MSG_CR | MSG_LF, "Receiver is capable of true full duplex");
  290.       if (receiver_flags & RZ_FLAG_CANOVIO)
  291.     msg(MSG_CR | MSG_LF, "Receiver can receive data during disk I/O");
  292.       if (receiver_flags & RZ_FLAG_CANBRK)
  293.     msg(MSG_CR | MSG_LF, "Receiver can send break signal");
  294.       if (receiver_flags & RZ_FLAG_CANCRY)
  295.     msg(MSG_CR | MSG_LF, "Receiver can decrypt");
  296.       if (receiver_flags & RZ_FLAG_CANLZW)
  297.     msg(MSG_CR | MSG_LF, "Receiver can uncompress");
  298.       if (receiver_flags & RZ_FLAG_CANFC32) {
  299.     msg(MSG_CR | MSG_LF, "Receiver can use 32-bit frame checking");
  300.     if (p_cfg.attr & CFG_ALTERNATIVE_CHECKING)
  301.       msg(MSG_CR | MSG_LF, "Our parameters override, 16-bit frame checking will be used");
  302.       }
  303.       if (receiver_flags & RZ_FLAG_ESC_CTRL)
  304.     msg(MSG_CR | MSG_LF, "Receiver wants control characters to be escaped");
  305.       if (receiver_flags & RZ_FLAG_ESC_8TH)
  306.     msg(MSG_CR | MSG_LF, "Receiver wants 8th bit to be escaped");
  307.     }
  308.     break;
  309.  
  310.   case PS_Z_RECEIVER_WINDOW_SIZE:
  311.     if (receiver_window_size != arg_list[0]) {
  312.       if (receiver_window_size != -1)
  313.     msg(MSG_CR | MSG_LF, "Receiver has changed its window parameters");
  314.       receiver_window_size = arg_list[0];
  315.       if (receiver_window_size == 0)
  316.     msg(MSG_CR | MSG_LF, "Receiver can accept full streaming");
  317.       else
  318.     msg(MSG_CR | MSG_LF, "Receiver wants a frame window of %lu bytes to be used", receiver_window_size);
  319.       if (p_cfg.blk_size &&
  320.       p_cfg.blk_size != receiver_window_size)
  321.     msg(MSG_CR | MSG_LF, "Our parameters override, a frame window of %lu bytes will be used", p_cfg.blk_size);
  322.     }
  323.     break;
  324.  
  325.   case PS_Z_SENDER_FLAGS:
  326.     if (arg_list[0] & RZ_FLAG_ESC_CTRL)
  327.       msg(MSG_LF, "Sender wants control characters to be escaped");
  328.     if (arg_list[0] & RZ_FLAG_ESC_8TH)
  329.       msg(MSG_LF, "Sender wants 8th bit to be escaped");
  330.     break;
  331.  
  332.   case PS_SERVER_WAITING:
  333.     if (arg_list[0] == opt_wait) {
  334.       if (opt_wait) {
  335.     msg(MSG_LF, "Timeout");
  336.     DosBeep(750, 1000);
  337.       } else
  338.     msg(MSG_LF, "No connection, try specifying a waiting time (with -wait option)");
  339.       aborted = 1;
  340.     } else {
  341.       msg(MSG_CR, "Waiting for connect (%lu secs)", arg_list[0] + 1);
  342.       if (!opt_quiet)
  343.     DosBeep(250, 20);
  344.       DosSleep(1000);
  345.     }
  346.     break;
  347.  
  348.   case PS_FILE_SKIPPED:
  349.     msg(MSG_LF, "File skipped by receiver request");
  350.     break;
  351.  
  352.   case PS_Z_SERIAL_NUM:
  353.     if (p_cfg.attr & CFG_QUERY_SERIAL_NUM) /* Let's not show it, if not */
  354.                        /* explicitly asked to */
  355.       msg(MSG_LF, "Serial number of the receiver is %lu", arg_list[0]);
  356.     remote_serial_num = arg_list[0];
  357.     break;
  358.  
  359.   default:
  360.     msg(MSG_LF, "Got unknown P_STATUS: %lu", type);
  361.     break;
  362.   }
  363.   if (aborted) {        /* User has pressed CTRL-C */
  364.     we_aborted = 1;
  365.     aborted = 0;        /* Once is enough */
  366.     return(1);
  367.   }
  368.   return(0);
  369. }
  370.  
  371. BOOLEAN s_open_func(U8 **path, U32 *length, U32 *date, U32 *mode,
  372.             U32 *f_left, U32 *b_left,
  373.             U8 *zconv, U8 *zmanag, U8 *ztrans) {
  374.  
  375.   APIRET rc;
  376.   struct stat statbuf;
  377.  
  378.   while (1) {
  379.     if (tl->c == NULL) {
  380.       *path = NULL;
  381.       return(0);
  382.     }
  383.     rc = DosAllocMem((void **)path, 4096, PAG_COMMIT | PAG_WRITE | PAG_READ);
  384.     if (rc)
  385.       os2_error(P_ERROR_DOSALLOCMEM, rc,
  386.         MODULE_CALLBACK, __LINE__,
  387.         (U8 *)4096);
  388.  
  389.     full_path = tl->c->path;
  390.     if (opt_paths)
  391.       strcpy(*path, tl->c->path);
  392.     else
  393.       strcpy(*path, tl->c->name);
  394.     tl->c = tl->c->n;
  395.     
  396.     if ((brwf = brw_open(full_path,
  397.              opt_filebuf, opt_filebuf,
  398.              O_RDONLY | O_BINARY, SH_DENYNO)) == NULL) {
  399.       perror(full_path);
  400.     } else {
  401.       *length = filelength(brwf->fd);
  402.       fstat(brwf->fd, &statbuf);
  403.       *date = statbuf.st_mtime;
  404.       *mode = statbuf.st_mode;
  405.       *f_left = files_left;
  406.       *b_left = bytes_left;
  407.       if (p_cfg.protocol_type == PROTOCOL_Z) {
  408.     /**********************/
  409.     /* Conversion options */
  410.     /**********************/
  411.     *zconv = 0;
  412.     if (opt_text)
  413.       *zconv |= Z_CONVERSION_TEXT;
  414.     else
  415.       *zconv |= Z_CONVERSION_BINARY;
  416.     if (opt_resume)
  417.       *zconv = Z_CONVERSION_RESUME;
  418.  
  419.     /**********************/
  420.     /* Management options */
  421.     /**********************/
  422.     *zmanag = 0;
  423.     if (opt_existing)
  424.       *zmanag |= Z_MANAGEMENT_MUST_EXIST;
  425.     *zmanag |= opt_management;
  426.  
  427.     /*********************/
  428.     /* Transport options */
  429.     /*********************/
  430.     *ztrans = 0;
  431.       }
  432.       if (opt_mileage) {
  433.     if (opt_speed)
  434.       msg(MSG_LF,
  435.           "Total of %lu files and %lu bytes (%s) left to transfer",
  436.           files_left, bytes_left, d_time(bytes_left / (opt_speed / 10)));
  437.     else
  438.       msg(MSG_LF, "Total of %lu files and %lu bytes left to transfer",
  439.           files_left, bytes_left);
  440.       }
  441.       if (opt_speed) 
  442.     msg(MSG_CR | MSG_LF, "Sending %s, %lu bytes, %s",
  443.         full_path, *length, d_time(*length / (opt_speed / 10)));
  444.       else
  445.     msg(MSG_CR | MSG_LF, "Sending %s, %lu bytes", full_path, *length);
  446.       time(&t_started);
  447.       return(0);
  448.     }
  449.   }
  450. }
  451.  
  452. /* Finds an unique name for the file */
  453.  
  454. BOOLEAN solve_name_for_file(U8 **path, U32 open_mode) {
  455.  
  456.   U32 i;
  457.   U32 org_i;
  458.   U32 n = 0;
  459.   U32 m = 10;
  460.   BOOLEAN extending = 1;
  461.  
  462.   org_i = strlen(*path);
  463.   i = org_i;
  464.   while (1) {
  465.     if (extending) {
  466.       sprintf(&(*path)[i], "-%lu", n);
  467.       n++;
  468.     } else {
  469.       sprintf(&(*path)[i], "%lu", n);
  470.       n++;
  471.       if (n == m) {
  472.     i--;
  473.     m = n * 10;
  474.       }
  475.     }
  476.     if ((brwf = brw_open(*path,
  477.              opt_filebuf, opt_filebuf,
  478.              O_CREAT | O_WRONLY | O_EXCL | open_mode,
  479.              SH_DENYWR, S_IWRITE)) != NULL)
  480.       break;
  481. #ifdef __EMX__
  482.     if (errno == ENAMETOOLONG) {
  483.       extending = 0;
  484.       i = org_i - 1;            /* We'll start from the beginning */
  485.       n = 0;
  486.       m = 10;
  487.     } else if (errno != EEXIST) {
  488.       /* error, the reason for brw_open to fail was */
  489.       /* something else than that the file already exists  */
  490.       return(1);
  491.     }
  492. #else /* __EMX__ */
  493.     /* Renaming on FAT doesn't work with ICC this way, haven't bothered to */
  494.     /* kludge it to work... */
  495.     return(0);
  496. #endif /* __EMX__ */
  497.   }
  498.   msg(MSG_LF, "File already exists, renaming to %s", *path);
  499.   return(0);
  500. }
  501.  
  502. U32 r_open_func(U8 **path, U32 length, U32 date, U32 mode,
  503.         U32 f_left, U32 b_left,
  504.         U8 zconv, U8 zmanag, U8 ztrans,
  505.         U32 *offset) {
  506.  
  507.   BOOLEAN path_was_null;
  508.   U32 management = 0;
  509.   U32 open_mode = 0;
  510.   APIRET rc;
  511.   struct stat statbuf;
  512.  
  513.   if (*path == NULL) {        /* Xmodem receive? */
  514.     rc = DosAllocMem((void **)path, 4096,
  515.              PAG_COMMIT | PAG_WRITE | PAG_READ);
  516.     if (rc)
  517.       os2_error(P_ERROR_DOSALLOCMEM, rc,
  518.         MODULE_CALLBACK, __LINE__,
  519.         (U8 *)4096);
  520.  
  521.     strcpy(*path, tl->c->path);
  522.     tl->c = tl->c->n;
  523.  
  524.     path_was_null = 1;
  525.   } else
  526.     path_was_null = 0;
  527.   
  528.   if (!opt_paths)
  529.     strip_drive_and_dir(*path);
  530.   else {
  531.     if (opt_create && create_dirs(*path)) {
  532.       msg(MSG_LF, "%s: %s, %s...", *path, strerror(errno),
  533.       p_cfg.protocol_type == PROTOCOL_Z ? "skipping" : "aborting");
  534.       rc = DosFreeMem((void *)*path);
  535.       if (rc)
  536.     os2_error(P_ERROR_DOSFREEMEM, rc,
  537.           MODULE_CALLBACK, __LINE__,
  538.           NULL);
  539.  
  540.       *path = NULL;
  541.       return(0);
  542.     }
  543.   }
  544.   if (opt_mileage) {
  545.     if (f_left || b_left) {
  546.       if (opt_speed)
  547.     msg(MSG_LF,
  548.         "Total of %lu files and %lu bytes (%s) left to transfer",
  549.         f_left, b_left, d_time(b_left / (opt_speed / 10)));
  550.       else
  551.     msg(MSG_LF, "Total of %lu files and %lu bytes left to transfer",
  552.         f_left, b_left);
  553.     }
  554.   }
  555.   if (p_cfg.protocol_type == PROTOCOL_Z && opt_options) {
  556.     switch (zconv) {
  557.     case Z_CONVERSION_UNDEFINED:
  558.       break;
  559.  
  560.     case Z_CONVERSION_BINARY:
  561.       msg(MSG_LF, "Sender suggests a binary conversion to be used");
  562.       break;
  563.       
  564.     case Z_CONVERSION_TEXT:
  565.       msg(MSG_LF, "Sender suggests a text conversion to be used");
  566.       break;
  567.  
  568.     case Z_CONVERSION_RESUME:
  569.       msg(MSG_LF, "Sender suggests that the file transfer should be resumed");
  570.       break;
  571.  
  572.     default:
  573.       msg(MSG_LF, "Unknown conversion option received: %lu", zconv);
  574.       break;
  575.     }
  576.     switch (zmanag & Z_MANAGEMENT_MASK) {
  577.     case Z_MANAGEMENT_UNDEFINED:
  578.       break;
  579.  
  580.     case Z_MANAGEMENT_UPDATE:
  581.       msg(MSG_LF, "Sender wants to update older and shorter files");
  582.       break;
  583.  
  584.     case Z_MANAGEMENT_COMPARE:
  585.       msg(MSG_LF,
  586.       "Sender wants to compare possibly existing files before replacing");
  587.       break;
  588.  
  589.     case Z_MANAGEMENT_APPEND:
  590.       msg(MSG_LF, "Sender wants to append to already existing files");
  591.       break;
  592.  
  593.     case Z_MANAGEMENT_REPLACE:
  594.       msg(MSG_LF, "Sender wants to replace already existing files");
  595.       break;
  596.  
  597.     case Z_MANAGEMENT_NEWER:
  598.       msg(MSG_LF, "Sender wants to update older files");
  599.       break;
  600.  
  601.     case Z_MANAGEMENT_DIFFERENT:
  602.       msg(MSG_LF,
  603.       "Sender wants to replace files with different dates and lengths");
  604.       break;
  605.  
  606.     case Z_MANAGEMENT_PROTECT:
  607.       msg(MSG_LF, "Sender does not want to replace already existing files");
  608.       break;
  609.  
  610.     default:
  611.       msg(MSG_LF, "Unknown management option received: %lu", zmanag);
  612.       break;
  613.     }
  614.     if (zmanag & Z_MANAGEMENT_MUST_EXIST)
  615.       msg(MSG_LF, "Sender wants to transfer only already existing files");
  616.     switch (ztrans) {
  617.     case Z_TRANSPORT_UNDEFINED:
  618.       break;
  619.  
  620.     case Z_TRANSPORT_LZW:
  621.       msg(MSG_LF, "Sender wants to use Lempel-Ziv compression");
  622.       break;
  623.  
  624.     case Z_TRANSPORT_CRYPT:
  625.       msg(MSG_LF, "Sender wants to use encryption");
  626.       break;
  627.  
  628.     case Z_TRANSPORT_RLE:
  629.       msg(MSG_LF, "Sender wants to use RLE compression");
  630.       break;
  631.  
  632.     default:
  633.       msg(MSG_LF, "Unknown transport option received: %lu", ztrans);
  634.       break;
  635.     }
  636.   }
  637.   /******************************/
  638.   /* Process conversion options */
  639.   /******************************/
  640.   if (zconv == Z_CONVERSION_TEXT || opt_text)
  641.     open_mode |= O_TEXT;
  642.   else
  643.     open_mode |= O_BINARY;
  644.   /******************************/
  645.   /* Process management options */
  646.   /******************************/
  647.   if (!(zmanag & Z_MANAGEMENT_MUST_EXIST) && !opt_existing)
  648.     open_mode |= O_CREAT;
  649.   management = (zmanag & Z_MANAGEMENT_MASK);
  650.   if (opt_management)               /* If management option specified */
  651.                        /* on the command-line */
  652.     management = opt_management;       /* Command-line overrides remote's */
  653.                        /* options */
  654.   if (!management && zconv != Z_CONVERSION_RESUME && !opt_resume) {
  655.     /* If no management option or resume specified, we'll default to */
  656.     /* protecting existing files... */
  657.     management = Z_MANAGEMENT_PROTECT;
  658.   }
  659.   if (length != -1) {
  660.     if (opt_speed != 0) {
  661.       msg(MSG_CR | MSG_LF, "Receiving %s, %lu bytes, %s",
  662.       *path, length, d_time(length / (opt_speed / 10)));
  663.     } else
  664.       msg(MSG_CR | MSG_LF, "Receiving %s, %lu bytes", *path, length);
  665.   } else
  666.     msg(MSG_CR | MSG_LF, "Receiving %s", *path);
  667.  
  668.   if (!path_was_null && tl != NULL) {
  669.     if (!tl_exists(tl, *path)) {
  670.       msg(MSG_LF, "File not specified on command-line, %s...",
  671.       p_cfg.protocol_type == PROTOCOL_Z ? "skipping" : "aborting");
  672.  
  673.       rc = DosFreeMem((void *)*path);
  674.       if (rc)
  675.     os2_error(P_ERROR_DOSFREEMEM, rc,
  676.           MODULE_CALLBACK, __LINE__,
  677.           NULL);
  678.  
  679.       *path = NULL;
  680.       return(0);
  681.     }
  682.   }
  683.   add_recv_dir_to_path(path);
  684.  
  685.   if ((brwf = brw_open(*path,
  686.                opt_filebuf, opt_filebuf,
  687.                O_WRONLY | O_EXCL | open_mode,
  688.                SH_DENYWR, S_IWRITE)) == NULL) {
  689.     if (errno != EEXIST) {    /* The reason for brw_open() to fail was */
  690.                 /* something else than that the file */
  691.                 /* already exists */
  692.       msg(MSG_LF, "%s: %s, %s...", *path, strerror(errno),
  693.       p_cfg.protocol_type == PROTOCOL_Z ? "skipping" : "aborting");
  694.       rc = DosFreeMem((void *)*path);
  695.       if (rc)
  696.     os2_error(P_ERROR_DOSFREEMEM, rc,
  697.           MODULE_CALLBACK, __LINE__,
  698.           NULL);
  699.  
  700.       *path = NULL;
  701.       return(0);
  702.     }
  703.     switch (management) {
  704.     case Z_MANAGEMENT_UNDEFINED:
  705.       /* Do nothing */
  706.       break;
  707.  
  708.     case Z_MANAGEMENT_UPDATE:        /* Only if newer or longer */
  709.       stat(*path, &statbuf);
  710.       if (statbuf.st_size >= length && statbuf.st_mtime >= date) {
  711.     msg(MSG_LF, "Up to date file already exists, %s...",
  712.       p_cfg.protocol_type == PROTOCOL_Z ? "skipping" : "aborting");
  713.     rc = DosFreeMem((void *)*path);
  714.     if (rc)
  715.       os2_error(P_ERROR_DOSFREEMEM, rc,
  716.             MODULE_CALLBACK, __LINE__,
  717.             NULL);
  718.     
  719.     *path = NULL;
  720.     return(0);
  721.       }
  722.       break;
  723.  
  724.     case Z_MANAGEMENT_NEWER:        /* Only if newer */
  725.       stat(*path, &statbuf);
  726.       if (statbuf.st_mtime >= date) {
  727.     msg(MSG_LF, "Up to date file already exists, %s...",
  728.       p_cfg.protocol_type == PROTOCOL_Z ? "skipping" : "aborting");
  729.     rc = DosFreeMem((void *)*path);
  730.     if (rc)
  731.       os2_error(P_ERROR_DOSFREEMEM, rc,
  732.             MODULE_CALLBACK, __LINE__,
  733.             NULL);
  734.     
  735.     *path = NULL;
  736.     return(0);
  737.       }
  738.       break;
  739.  
  740.     case Z_MANAGEMENT_DIFFERENT:    /* Only if date if different */
  741.       stat(*path, &statbuf);
  742.       if (statbuf.st_mtime == date) {
  743.     msg(MSG_LF, "File with an identical date exists, %s...",
  744.       p_cfg.protocol_type == PROTOCOL_Z ? "skipping" : "aborting");
  745.     rc = DosFreeMem((void *)*path);
  746.     if (rc)
  747.       os2_error(P_ERROR_DOSFREEMEM, rc,
  748.             MODULE_CALLBACK, __LINE__,
  749.             NULL);
  750.     
  751.     *path = NULL;
  752.     return(0);
  753.       }
  754.       if (statbuf.st_size == length) {
  755.     msg(MSG_LF, "File with an identical size exists, %s...",
  756.       p_cfg.protocol_type == PROTOCOL_Z ? "skipping" : "aborting");
  757.     rc = DosFreeMem((void *)*path);
  758.     if (rc)
  759.       os2_error(P_ERROR_DOSFREEMEM, rc,
  760.             MODULE_CALLBACK, __LINE__,
  761.             NULL);
  762.     
  763.     *path = NULL;
  764.     return(0);
  765.       }
  766.       break;
  767.  
  768.     case Z_MANAGEMENT_APPEND:
  769.       msg(MSG_LF, "File already exists, appending...");
  770.       open_mode |= O_APPEND;
  771.       break;
  772.  
  773.     case Z_MANAGEMENT_REPLACE:
  774.       msg(MSG_LF, "File already exists, overwriting...");
  775.       open_mode |= O_TRUNC;
  776.       break;
  777.  
  778.     case Z_MANAGEMENT_PROTECT:
  779.       msg(MSG_LF, "File already exists, %s...",
  780.       p_cfg.protocol_type == PROTOCOL_Z ? "skipping" : "aborting");
  781.       rc = DosFreeMem((void *)*path);
  782.       if (rc)
  783.     os2_error(P_ERROR_DOSFREEMEM, rc,
  784.           MODULE_CALLBACK, __LINE__,
  785.           NULL);
  786.       *path = NULL;
  787.       return(0);
  788.  
  789.     case Z_MANAGEMENT_RENAME:
  790.       if (solve_name_for_file(path, open_mode)) { /* brwf gets opened here */
  791.     msg(MSG_LF, "%s: %s, %s...", *path, strerror(errno),
  792.         p_cfg.protocol_type == PROTOCOL_Z ? "skipping" : "aborting");
  793.     rc = DosFreeMem((void *)*path);
  794.     if (rc)
  795.       os2_error(P_ERROR_DOSFREEMEM, rc,
  796.             MODULE_CALLBACK, __LINE__,
  797.             NULL);
  798.     *path = NULL;
  799.     return(0);
  800.       }
  801.       /* brwf is open now! */
  802.       break;
  803.  
  804.     case Z_MANAGEMENT_COMPARE:
  805.       /* Do nothing */
  806.       break;
  807.     }
  808.     if (zconv == Z_CONVERSION_RESUME || opt_resume)
  809.       open_mode |= O_APPEND;
  810.  
  811.     if (brwf == NULL) {        /* brwf is not yet opened */
  812.       if ((brwf = brw_open(*path,
  813.                opt_filebuf, opt_filebuf,
  814.                O_CREAT | O_WRONLY | open_mode,
  815.                SH_DENYWR, S_IWRITE)) == NULL) {
  816.     msg(MSG_LF, "%s: %s, %s...", *path, strerror(errno),
  817.         p_cfg.protocol_type == PROTOCOL_Z ? "skipping" : "aborting");
  818.     rc = DosFreeMem((void *)*path);
  819.     if (rc)
  820.       os2_error(P_ERROR_DOSFREEMEM, rc,
  821.             MODULE_CALLBACK, __LINE__,
  822.             NULL);
  823.  
  824.     *path = NULL;
  825.     return(0);
  826.       }
  827.       if (open_mode & O_APPEND) {
  828.     if (p_cfg.protocol_type == PROTOCOL_Z &&
  829.         (zconv == Z_CONVERSION_RESUME || opt_resume)) { /* Are we crash- */
  830.                                   /* recovering? */
  831.       *offset = filelength(brwf->fd);
  832.       if (*offset != length)
  833.         msg(MSG_LF, "Crash recovery at %lu", *offset);
  834.       else {
  835.         msg(MSG_LF, "We have the whole file already, skipping..."); 
  836.         brw_close(&brwf);
  837.         rc = DosFreeMem((void *)*path);
  838.         if (rc)
  839.           os2_error(P_ERROR_DOSFREEMEM, rc,
  840.             MODULE_CALLBACK, __LINE__,
  841.             NULL);
  842.         
  843.         *path = NULL;
  844.         return(0);
  845.       }
  846.     } else {            /* Not resuming => appending */
  847.       msg(MSG_LF, "Appending at %lu", filelength(brwf->fd));
  848.       if (offset != NULL)    /* If offset is non-null, we're using Zmodem */
  849.         *offset = 0;    /* Tell the remote to start sending from the */
  850.                 /* beginning of the file */
  851.     }
  852.       }
  853.     }
  854.   } else {
  855.     if (offset != NULL)        /* Zmodem receive? */
  856.       *offset = 0;
  857.   }
  858.   time(&t_started);
  859.   return(0);
  860. }
  861.  
  862. U32 close_func(U8 **path,
  863.            U32 length,
  864.            U32 date,
  865.            U32 retransmits,
  866.            BOOLEAN successful,
  867.            U32 offset) {
  868.  
  869.   U8 id;
  870.   S32 rw_ret;
  871.   time_t t_now;
  872.   U32 cps;
  873.   U32 ret_val = 0;
  874.   struct utimbuf times;
  875.   APIRET rc;
  876.  
  877.   time(&t_now);
  878.   if ((rw_ret = brw_flush(brwf))) {
  879.     if (rw_ret == -1)
  880.       fprintf(stderr, "\rFailed to write to file, %s\n", strerror(errno));
  881.     else
  882.       fprintf(stderr, "\rFailed to write to file, disk full?\n");
  883.     ret_val = 1;
  884.   }
  885.   brw_close(&brwf);
  886.   
  887.   if (!opt_touch && date != -1) {    /* Set the file date */
  888.     time(×.actime);
  889.     times.modtime = date;
  890. #ifdef __EMX__
  891.     utime(*path, ×);
  892. #else /* __EMX__ */
  893.     _utime(*path, ×);
  894. #endif /* __EMX__ */
  895.   }
  896.   if (p_cfg.transfer_direction == DIR_SEND) {
  897.     files_left--;
  898.     bytes_left -= length;
  899.   }
  900.   if (offset) {
  901.     cps = (t_now == t_started ?
  902.        offset : offset / (t_now - t_started));
  903.     msg(MSG_CR | MSG_LF, "%lu bytes, %s, %lu CPS%s",
  904.     offset, d_time(t_now - t_started), cps,
  905.     !successful ? ", Transfer incomplete" : "");
  906.  
  907.     if (opt_dszlog != NULL) {
  908.       if (dszlog_stream == NULL &&
  909.       (dszlog_stream = fopen(opt_dszlog, "w")) == NULL) {
  910.     perror(opt_dszlog);
  911.     ret_val = 1;
  912.       } else {
  913.     if (successful) {
  914.       switch (p_cfg.protocol_type) {
  915.       case PROTOCOL_X:
  916.         id = 'x';
  917.         break;
  918.         
  919.       case PROTOCOL_Y:
  920.         id = 'y';
  921.         break;
  922.         
  923.       case PROTOCOL_G:
  924.         id = 'g';
  925.         break;
  926.         
  927.       case PROTOCOL_Z:
  928.       default:        /* Just to shut up the compiler */
  929.         id = 'z';
  930.         break;
  931.       }
  932.       if (p_cfg.transfer_direction == DIR_RECV) /* The protocol id */
  933.                             /* should be in */
  934.                             /* uppercase when */
  935.                             /* receiving...*/
  936.         id = toupper(id);
  937.     } else if (carrier_lost)
  938.       id = 'L';            /* Carrier lost */
  939.     else
  940.       id = 'E';            /* Other error */
  941.     
  942.     fprintf(dszlog_stream,
  943.         "%c %6lu %5lu bps %4lu cps %3lu errors     0 %4lu %12s %ld\n",
  944.         id,
  945.         successful ? length : offset,
  946.         opt_speed,
  947.         cps,
  948.         retransmits,
  949.         1024L, /* block_size */
  950.         full_path != NULL ? full_path : *path,
  951.         remote_serial_num);
  952.       }
  953.     }
  954.   }
  955.   if (p_cfg.transfer_direction == DIR_RECV &&
  956.       opt_clean &&
  957.       !successful) {
  958.     msg(MSG_LF, "Deleting: %s", *path);
  959.     unlink(*path);
  960.   }
  961.   rc = DosFreeMem(*path);
  962.   if (rc)
  963.     os2_error(P_ERROR_DOSFREEMEM, rc,
  964.           MODULE_CALLBACK, __LINE__,
  965.           NULL);
  966.  
  967.   *path = NULL;
  968.   return(ret_val);
  969. }
  970.  
  971. U32 seek_func(U32 pos) {
  972.  
  973.   if (brw_seek(brwf, pos) == -1) {
  974.     fprintf(stderr, "\rFailed to seek in file, %s\n", strerror(errno));
  975.     return(1);
  976.   } else
  977.     return(0);
  978. }
  979.  
  980. U32 read_func(U8 *buf, U32 bytes_wanted, U32 *bytes_got) {
  981.  
  982.   if ((*bytes_got = brw_read(brwf, buf, bytes_wanted)) == -1) {
  983.     fprintf(stderr, "\rFailed to read from file, %s\n", strerror(errno));
  984.     return(1);
  985.   } else
  986.     return(0);
  987. }
  988.  
  989. U32 write_func(U8 *buf, U32 bytes) {
  990.  
  991.   U32 rw_ret;
  992.  
  993.   if ((rw_ret = brw_write(brwf, buf, bytes)) == -1) {
  994.     fprintf(stderr, "\rFailed to write to file, %s\n", strerror(errno));
  995.     return(1);
  996.   } else if (rw_ret) {
  997.     fprintf(stderr, "\rFailed to write to file, disk full?\n");
  998.     return(1);
  999.   } else
  1000.     return(0);
  1001. }
  1002.  
  1003.