home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / bin / p205.zip / exesrc / p.c < prev    next >
C/C++ Source or Header  |  1994-12-18  |  15KB  |  669 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.    The main module of P.EXE. Parses the command-line and calls P.DLL.
  8. */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include "typedefs.h"
  15. #include "p.h"
  16. #include "callback.h"
  17. #include "p_dll.h"
  18. #include "tcpipapi.h"
  19. #include "global.h"
  20. #include "common.h"
  21. #include "usage.h"
  22.  
  23. #define SERIAL_NUM    0    /* Our serial number, zero for none */
  24.  
  25. /* Stuff needed for command-line parsing */
  26.  
  27. enum {
  28.  
  29.   CFG_ENTRY_TYPE,
  30.  
  31.   CFG_ENTRY_DEVICE,
  32.   CFG_ENTRY_HOST,
  33.   CFG_ENTRY_PORT,
  34.   CFG_ENTRY_SERVER,
  35.   CFG_ENTRY_WAIT,
  36.   CFG_ENTRY_SHARE,
  37.  
  38.   CFG_ENTRY_HANDLE,
  39.  
  40.   CFG_ENTRY_LOOSE,
  41.   CFG_ENTRY_TELNET,
  42.  
  43.   CFG_ENTRY_RECEIVE,
  44.   CFG_ENTRY_SEND,
  45.  
  46.   CFG_ENTRY_PROTOCOL,
  47.   CFG_ENTRY_ESCAPE,
  48.   CFG_ENTRY_ALTERNATIVE,
  49.   CFG_ENTRY_KILO,
  50.   CFG_ENTRY_WINDOW,
  51.   CFG_ENTRY_AUTOMATIC,
  52.   CFG_ENTRY_SERIAL,
  53.   CFG_ENTRY_ATTENTION,
  54.  
  55.   CFG_ENTRY_COMMBUFS,
  56.   CFG_ENTRY_COMMINBUF,
  57.   CFG_ENTRY_COMMOUTBUF,
  58.   CFG_ENTRY_FILEBUF,
  59.  
  60.   CFG_ENTRY_SPEED,
  61.   CFG_ENTRY_MILEAGE,
  62.   CFG_ENTRY_OPTIONS,
  63.   CFG_ENTRY_HEADERS,
  64.   CFG_ENTRY_FRAMEENDS,
  65.   CFG_ENTRY_NOTE,
  66.  
  67.   CFG_ENTRY_QUIET,
  68.   CFG_ENTRY_PRIORITY,
  69.  
  70.   CFG_ENTRY_DSZLOG,
  71.   CFG_ENTRY_PAUSE,
  72.  
  73.   CFG_ENTRY_DIRECTORY,
  74.   CFG_ENTRY_PATHS,
  75.   CFG_ENTRY_CREATE,
  76.   CFG_ENTRY_CLEAN,
  77.   CFG_ENTRY_TOUCH,
  78.   CFG_ENTRY_RECURSIVE,
  79.  
  80.   CFG_ENTRY_TEXT,
  81.   CFG_ENTRY_RESUME,
  82.   CFG_ENTRY_EXISTING,
  83.   CFG_ENTRY_UPDATE,
  84.   CFG_ENTRY_APPEND,
  85.   CFG_ENTRY_REPLACE,
  86.   CFG_ENTRY_NEWER,
  87.   CFG_ENTRY_DIFFERENT,
  88.   CFG_ENTRY_PROTECT,
  89.   CFG_ENTRY_RENAME,
  90.  
  91.   CFG_ENTRIES
  92. };
  93.  
  94. typedef struct _CFG_ENTRY {
  95.  
  96.   U8 *str;
  97.   U32 num_of_args;
  98.  
  99. } CFG_ENTRY;
  100.  
  101. CFG_ENTRY cfg_entry[CFG_ENTRIES] = {
  102.  
  103.   { "type", 1 },
  104.  
  105.   { "device", 1 },
  106.   { "host", 1 },
  107.   { "port", 1 },
  108.   { "server", 0 },
  109.   { "wait", 1 },
  110.   { "share", 0 },
  111.  
  112.   { "handle", 1 },
  113.  
  114.   { "loose", 0 },
  115.   { "telnet", 0 },
  116.  
  117.   { "receive", 0 },
  118.   { "send", 0 },
  119.  
  120.   { "protocol", 1 },
  121.   { "escape", 1 },
  122.   { "alternative", 0 },
  123.   { "kilo", 0 },
  124.   { "window", 1 },
  125.   { "automatic", 0 },
  126.   { "serial", 0 },
  127.   { "attention", 1 },
  128.  
  129.   { "commbufs", 1 },
  130.   { "comminbuf", 1 },
  131.   { "commoutbuf", 1 },
  132.   { "filebuf", 1 },
  133.  
  134.   { "speed", 1 },
  135.   { "mileage", 0 },
  136.   { "options", 0 },
  137.   { "headers", 0 },
  138.   { "frameends", 0 },
  139.   { "note", 1 },
  140.  
  141.   { "quiet", 0 },
  142.   { "priority", 2 },
  143.  
  144.   { "dszlog", 1 },
  145.   { "pause", 0 },
  146.  
  147.   { "directory", 1 },
  148.   { "paths", 0 },
  149.   { "create", 0 },
  150.   { "clean", 0 },
  151.   { "touch", 0 },
  152.   { "recursive", 0 },
  153.  
  154.   { "text", 0 },
  155.   { "resume", 0 },
  156.   { "existing", 0 },
  157.   { "update", 0 },
  158.   { "append", 0 },
  159.   { "replace", 0 },
  160.   { "newer", 0 },
  161.   { "different", 0 },
  162.   { "protect", 0 },
  163.   { "rename", 0 },
  164. };
  165.  
  166. U8 *dev_type_str[] = {
  167.  
  168.   "async",
  169.   "pipe",
  170.   "socket"
  171. };
  172.  
  173. U8 *protocol_str[] = {
  174.  
  175.   "Xmodem",
  176.   "Ymodem",
  177.   "Ymodem-g",
  178.   "Zmodem"
  179. };
  180.  
  181. U8 *escaping_str[] = {
  182.  
  183.   "controls",
  184.   "minimal"
  185. };
  186.  
  187. U8 *checking_str[] = {
  188.  
  189.   "crc32",
  190.   "crc16",
  191.   "checksum"
  192. };
  193.  
  194. /* Checks and reports possible inconsistency in command-line options */
  195.  
  196. U32 check_inconsistency(void) {
  197.  
  198.   if (!p_cfg.dev_handle) {
  199.     switch (p_cfg.dev_type) {
  200.     case DEV_TYPE_ASYNC:
  201.     case DEV_TYPE_PIPE:
  202.       if (p_cfg.dev_path == NULL) {
  203.     fprintf(stderr, "No communication device specified, use -device to specify one.\n");
  204.     return(1);
  205.       }
  206.       break;
  207.  
  208.     case DEV_TYPE_SOCKET:
  209.       if (!(p_cfg.attr & CFG_DEV_SERVER) && p_cfg.socket_host == NULL) {
  210.     fprintf(stderr,
  211.         "No host specified, use -host to specify one, or if acting\n"
  212.         "as a server, use -server option.\n");
  213.     return(1);
  214.       }
  215.       if (!p_cfg.socket_port) {
  216.     fprintf(stderr, "No port specified, use -port to specify one.\n");
  217.     return(1);
  218.       }
  219.       break;
  220.  
  221.     }
  222.   }
  223.   if (!p_cfg.transfer_direction) {
  224.     fprintf(stderr, "No transfer direction specified, use -receive or -send to specify one.\n");
  225.     return(1);
  226.   }
  227.   if (tl == NULL) {        /* No files specified */
  228.     if (p_cfg.transfer_direction == DIR_SEND) {
  229.       fprintf(stderr, "Files to be sent must be specified.\n");
  230.       return(1);
  231.     }
  232.     if (p_cfg.transfer_direction == DIR_RECV &&
  233.     p_cfg.protocol_type == PROTOCOL_X) {
  234.       fprintf(stderr, "Files to be received must be specified for Xmodem.\n");
  235.       return(1);
  236.     }
  237.   }
  238.   if ((p_cfg.attr & CFG_ESC_CTRL || p_cfg.attr & CFG_ESC_MINIMAL) &&
  239.       p_cfg.protocol_type != PROTOCOL_Z)
  240.     printf("-escape option ignored. Only Zmodem supports it.\n");
  241.  
  242.   if (p_cfg.attr & CFG_ALTERNATIVE_CHECKING &&
  243.       p_cfg.protocol_type == PROTOCOL_G)
  244.     printf("-alternative option ignored. Ymodem-g does not support it.\n");
  245.  
  246.   if (p_cfg.attr & CFG_1K_BLOCKS) {
  247.     if (p_cfg.protocol_type == PROTOCOL_Z)
  248.       printf("-kilo option ignored. Has no meaning to Zmodem transfers.\n");
  249.     else if (p_cfg.transfer_direction == DIR_RECV)
  250.       printf("-kilo option ignored. Sender will define the block size.\n");
  251.   }
  252.   
  253.   if (p_cfg.attr & CFG_SEND_RZ_CR && p_cfg.protocol_type != PROTOCOL_Z)
  254.     printf("-automatic option ignored. Only Zmodem supports it.\n");
  255.  
  256.   if (p_cfg.attr & CFG_QUERY_SERIAL_NUM && p_cfg.protocol_type != PROTOCOL_Z)
  257.     printf("-serial option ignored. Only Zmodem supports it.\n");
  258.   
  259.   if (p_cfg.attn_seq != NULL && p_cfg.protocol_type != PROTOCOL_Z)
  260.     printf("-attention option ignored. Only Zmodem supports it.\n");
  261.  
  262.   if (opt_mileage && p_cfg.protocol_type == PROTOCOL_X)
  263.     printf("-mileage option ignored. Xmodem does not support it.\n");
  264.  
  265.   if (opt_options && p_cfg.protocol_type != PROTOCOL_Z)
  266.     printf("-options option ignored. Only Zmodem supports it.\n");
  267.  
  268.   if (opt_headers && p_cfg.protocol_type != PROTOCOL_Z)
  269.     printf("-headers option ignored. Only Zmodem supports it.\n");
  270.  
  271.   if (opt_frameends && p_cfg.protocol_type != PROTOCOL_Z)
  272.     printf("-frameends option ignored. Only Zmodem supports it.\n");
  273.  
  274.   if (opt_resume && p_cfg.protocol_type != PROTOCOL_Z)
  275.     printf("-resume option ignored. Only Zmodem supports it.\n");
  276.  
  277.   if (opt_management & Z_MANAGEMENT_UPDATE &&
  278.       p_cfg.protocol_type == PROTOCOL_X)
  279.     printf("-update option ignored. Xmodem does not support it.\n");
  280.  
  281.   if (opt_management & Z_MANAGEMENT_NEWER &&
  282.       p_cfg.protocol_type == PROTOCOL_X)
  283.     printf("-newer option ignored. Xmodem does not support it.\n");
  284.  
  285.   if (opt_management & Z_MANAGEMENT_DIFFERENT &&
  286.       p_cfg.protocol_type == PROTOCOL_X)
  287.     printf("-different option ignored. Xmodem does not support it.\n");
  288.   return(0);
  289. }
  290.  
  291. U32 main(U32 argc, U8 *argv[]) {
  292.  
  293.   U32 argi;
  294.   U32 idx;
  295.   U32 priority_class;
  296.   U32 priority_delta;
  297.   U32 rc;
  298.  
  299.   if (argc < 2) {
  300.     printf(usage, argv[0]);
  301.     return(1);
  302.   }
  303.   /* Put default values to p_cfg */
  304.  
  305.   memset(&p_cfg, '\0', sizeof(P_CFG));
  306.   p_cfg.inbuf_size = 2048;
  307.   p_cfg.outbuf_size = 2048;
  308.   p_cfg.blk_size = 0;
  309.  
  310.   p_cfg.version = P_INTERFACE_VERSION;
  311.   p_cfg.attr = CFG_WATCH_CARRIER;
  312.   p_cfg.dev_type = DEV_TYPE_ASYNC;
  313.   p_cfg.protocol_type = PROTOCOL_Z;
  314.   p_cfg.serial_num = SERIAL_NUM;
  315.   p_cfg.attn_seq = NULL;    /* By default, we don't */
  316.                 /* use attention sequence */
  317.  
  318.   /* Parse the command-line */
  319.   argi = 1;
  320.   while (argi < argc) {
  321.     if (argv[argi][0] == '-') {
  322.       if (argv[argi][1] == '\0') /* It's a plain "-" */
  323.     break;
  324.  
  325.       for (idx = 0; idx < CFG_ENTRIES; idx++) {
  326.     if (strnicmp(&argv[argi][1],
  327.              cfg_entry[idx].str,
  328.              strlen(&argv[argi][1])) == 0)
  329.       break;
  330.       }
  331.       if (idx == CFG_ENTRIES) {
  332.     fprintf(stderr, "Unknown option \"%s\"\n", argv[argi]);
  333.     return(1);
  334.       }
  335.       argi++;
  336.       if (argc - argi < cfg_entry[idx].num_of_args) {
  337.     fprintf(stderr,
  338.         "Insufficient number of arguments for -%s option\n",
  339.         cfg_entry[idx].str);
  340.     return(1);
  341.       }
  342.       switch (idx) {
  343.       case CFG_ENTRY_TYPE:
  344.     for (idx = 0; idx < 3; idx++) {
  345.       if (strnicmp(argv[argi],
  346.                dev_type_str[idx],
  347.                strlen(argv[argi])) == 0)
  348.         break;
  349.     }
  350.     if (idx == 3) {
  351.       fprintf(stderr, "Unknown device type \"%s\"\n", argv[argi]);
  352.       return(1);
  353.     }
  354.     p_cfg.dev_type = idx + 1;
  355.     argi++;
  356.     break;
  357.  
  358.       case CFG_ENTRY_DEVICE:
  359.     p_cfg.dev_path = argv[argi];
  360.     argi++;
  361.     break;
  362.  
  363.       case CFG_ENTRY_HANDLE:
  364.     p_cfg.dev_handle = atol(argv[argi]);
  365.     argi++;
  366.     break;
  367.  
  368.       case CFG_ENTRY_RECEIVE:
  369.     p_cfg.transfer_direction = DIR_RECV;
  370.     break;
  371.  
  372.       case CFG_ENTRY_SEND:
  373.     p_cfg.transfer_direction = DIR_SEND;
  374.     break;
  375.  
  376.       case CFG_ENTRY_SERVER:
  377.     p_cfg.attr |= CFG_DEV_SERVER;
  378.     break;
  379.  
  380.       case CFG_ENTRY_PROTOCOL:
  381.     for (idx = 0; idx < 4; idx++)
  382.       if (strnicmp(argv[argi],
  383.                protocol_str[idx],
  384.                strlen(argv[argi])) == 0) {
  385.         break;
  386.     }
  387.     if (idx == 4) {
  388.       fprintf(stderr, "Unknown protocol \"%s\"\n", argv[argi]);
  389.       return(1);
  390.     }
  391.     p_cfg.protocol_type = idx + 1;
  392.     argi++;
  393.     break;
  394.  
  395.       case CFG_ENTRY_COMMBUFS:
  396.     p_cfg.inbuf_size = p_cfg.outbuf_size = atol(argv[argi]);
  397.     argi++;
  398.     break;
  399.  
  400.       case CFG_ENTRY_COMMINBUF:
  401.     p_cfg.inbuf_size = atol(argv[argi]);
  402.     argi++;
  403.     break;
  404.  
  405.       case CFG_ENTRY_COMMOUTBUF:
  406.     p_cfg.outbuf_size = atol(argv[argi]);
  407.     argi++;
  408.     break;
  409.  
  410.       case CFG_ENTRY_FILEBUF:
  411.     opt_filebuf = atol(argv[argi]);
  412.     argi++;
  413.     break;
  414.  
  415.       case CFG_ENTRY_HOST:
  416.     p_cfg.socket_host = argv[argi];
  417.     argi++;
  418.     break;
  419.  
  420.       case CFG_ENTRY_PORT:
  421.     p_cfg.socket_port = atol(argv[argi]);
  422.     argi++;
  423.     break;
  424.  
  425.       case CFG_ENTRY_SPEED:
  426.     opt_speed = atol(argv[argi]);
  427.     argi++;
  428.     break;
  429.  
  430.       case CFG_ENTRY_ESCAPE:
  431.     for (idx = 0; idx < 2; idx++)
  432.       if (strnicmp(argv[argi],
  433.                escaping_str[idx],
  434.                strlen(argv[argi])) == 0) {
  435.         break;
  436.     }
  437.     if (idx == 2) {
  438.       fprintf(stderr, "Unknown escaping \"%s\"\n", argv[argi]);
  439.       return(1);
  440.     }
  441.     switch (idx) {
  442.     case 0:
  443.       p_cfg.attr |= CFG_ESC_CTRL;
  444.       break;
  445.  
  446.     case 1:
  447.       p_cfg.attr |= CFG_ESC_MINIMAL;
  448.       break;
  449.     }
  450.     argi++;
  451.     break;
  452.  
  453.       case CFG_ENTRY_ALTERNATIVE:
  454.     p_cfg.attr |= CFG_ALTERNATIVE_CHECKING;
  455.     break;
  456.  
  457.       case CFG_ENTRY_LOOSE:
  458.     if (p_cfg.attr & CFG_WATCH_CARRIER)
  459.       p_cfg.attr ^= CFG_WATCH_CARRIER;
  460.     break; 
  461.  
  462.       case CFG_ENTRY_DSZLOG:
  463.     opt_dszlog = argv[argi];
  464.     argi++;
  465.     break;
  466.     
  467.       case CFG_ENTRY_KILO:
  468.     p_cfg.attr |= CFG_1K_BLOCKS;
  469.     break;
  470.  
  471.       case CFG_ENTRY_PAUSE:
  472.     atexit(wait_for_keypress);
  473.     break;
  474.  
  475.       case CFG_ENTRY_RESUME:
  476.     opt_resume = 1;
  477.     break;
  478.  
  479.       case CFG_ENTRY_SHARE:
  480.     p_cfg.attr |= CFG_SHARED_DEVICE;
  481.     break;
  482.  
  483.       case CFG_ENTRY_CLEAN:
  484.     opt_clean = 1;
  485.     break;
  486.  
  487.       case CFG_ENTRY_PATHS:
  488.     opt_paths = 1;
  489.     break;
  490.  
  491.       case CFG_ENTRY_DIRECTORY:
  492.     opt_directory = argv[argi];
  493.     argi++;
  494.     break;
  495.  
  496.       case CFG_ENTRY_AUTOMATIC:
  497.     p_cfg.attr |= CFG_SEND_RZ_CR;
  498.     break;
  499.  
  500.       case CFG_ENTRY_WAIT:
  501.     opt_wait = atol(argv[argi]);
  502.     argi++;
  503.     break;
  504.  
  505.       case CFG_ENTRY_HEADERS:
  506.     opt_headers = 1;
  507.     break;
  508.  
  509.       case CFG_ENTRY_FRAMEENDS:
  510.     opt_frameends = 1;
  511.     break;
  512.  
  513.       case CFG_ENTRY_NOTE:
  514.     opt_note = argv[argi];
  515.     argi++;
  516.     break;
  517.  
  518.       case CFG_ENTRY_WINDOW:
  519.     p_cfg.blk_size = atol(argv[argi]);
  520.     if (p_cfg.blk_size) {
  521.       if (p_cfg.blk_size < 256 || p_cfg.blk_size > 65472) {
  522.         printf("Window size must be between 256 and 65472 bytes!\n");
  523.         return(1);
  524.       }
  525.       if (p_cfg.blk_size % 64) {
  526.         printf("Window size must a multiple of 64 bytes\n");
  527.         return(1);
  528.       }
  529.     }
  530.     argi++;
  531.     break;
  532.  
  533.       case CFG_ENTRY_PRIORITY:
  534.     priority_class = atol(argv[argi++]);
  535.     priority_delta = atol(argv[argi++]);
  536.     set_priority(priority_class, priority_delta);
  537.     break;
  538.  
  539.       case CFG_ENTRY_SERIAL:
  540.     p_cfg.attr |= CFG_QUERY_SERIAL_NUM;
  541.     break;
  542.  
  543.       case CFG_ENTRY_ATTENTION:
  544.     p_cfg.attn_seq = argv[argi++];
  545.     break;
  546.  
  547.       case CFG_ENTRY_TEXT:
  548.     opt_text = 1;
  549.     break;
  550.  
  551.       case CFG_ENTRY_TOUCH:
  552.     opt_touch = 1;
  553.     break;
  554.  
  555.       case CFG_ENTRY_RECURSIVE:
  556.     opt_recursive = 1;
  557.     break;
  558.  
  559.       case CFG_ENTRY_CREATE:
  560.     opt_create = 1;
  561.     break;
  562.  
  563.       case CFG_ENTRY_TELNET:
  564.     p_cfg.attr |= CFG_DEV_TELNET;
  565.     break;
  566.  
  567.       case CFG_ENTRY_QUIET:
  568.     opt_quiet = 1;
  569.     break;
  570.  
  571.       case CFG_ENTRY_EXISTING:
  572.     opt_existing = 1;
  573.     break;
  574.  
  575.       case CFG_ENTRY_UPDATE:
  576.     opt_management = Z_MANAGEMENT_UPDATE;
  577.     break;
  578.  
  579.       case CFG_ENTRY_APPEND:
  580.     opt_management = Z_MANAGEMENT_APPEND;
  581.     break;
  582.  
  583.       case CFG_ENTRY_REPLACE:
  584.     opt_management = Z_MANAGEMENT_REPLACE;
  585.     break;
  586.  
  587.       case CFG_ENTRY_NEWER:
  588.     opt_management = Z_MANAGEMENT_NEWER;
  589.     break;
  590.  
  591.       case CFG_ENTRY_DIFFERENT:
  592.     opt_management = Z_MANAGEMENT_DIFFERENT;
  593.     break;
  594.  
  595.       case CFG_ENTRY_PROTECT:
  596.     opt_management = Z_MANAGEMENT_PROTECT;
  597.     break;
  598.  
  599.       case CFG_ENTRY_RENAME:
  600.     opt_management = Z_MANAGEMENT_RENAME;
  601.     break;
  602.  
  603.       case CFG_ENTRY_MILEAGE:
  604.     opt_mileage = 1;
  605.     break;
  606.  
  607.       case CFG_ENTRY_OPTIONS:
  608.     opt_options = 1;
  609.     break;
  610.       }
  611.     } else            /* Argument does not begin with '-' */
  612.       break;
  613.   }
  614.   p_cfg.status_func = status_func;
  615.   p_cfg.r_open_func = r_open_func;
  616.   p_cfg.s_open_func = s_open_func;
  617.   p_cfg.close_func = close_func;
  618.   p_cfg.seek_func = seek_func;
  619.   p_cfg.read_func = read_func;
  620.   p_cfg.write_func = write_func;
  621.  
  622.   atexit(make_noise);        /* Install the beeper */
  623.  
  624.   /* Handles files and listfiles given after the options */
  625.   while (argi < argc) {
  626.     if (argv[argi][0] == '@')
  627.       tl_read_from_list(&tl,
  628.             p_cfg.transfer_direction == DIR_RECV ? 0 : 1,
  629.             argv[argi]);
  630.     else {
  631.       if (p_cfg.transfer_direction == DIR_RECV)
  632.     tl_add(&tl, argv[argi], 0);
  633.       else
  634.     tl_expanded_add(&tl, argv[argi]);
  635.     }
  636.     argi++;
  637.   }
  638.  
  639.   if (check_inconsistency())
  640.     return(1);
  641.  
  642.   if (p_cfg.transfer_direction == DIR_SEND) {
  643.     files_left = tl->cnt;
  644.     bytes_left = tl->size;
  645.   }
  646.   if (p_cfg.dev_type == DEV_TYPE_SOCKET)
  647.     load_tcpip();
  648.  
  649.   load_p_dll();
  650.  
  651.   install_interrupt_handler();
  652.  
  653.   msg(MSG_LF, "%s %s is being initiated",
  654.       protocol_str[p_cfg.protocol_type - 1],
  655.       p_cfg.transfer_direction == DIR_RECV ? "receiving" : "sending");
  656.  
  657.   rc = p_transfer(&p_cfg);
  658.   if (we_aborted)
  659.     msg(MSG_LF, "Transfer aborted");
  660.  
  661.   unload_p_dll();
  662.  
  663.   if (p_cfg.dev_type == DEV_TYPE_SOCKET)
  664.     unload_tcpip();
  665.  
  666.   return(rc);
  667. }
  668.  
  669.