Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

753 lines
17 KiB

  1. /* mdmx_snd.c -- Routines to handle xmodem sending for HA5G
  2. *
  3. * Copyright 1989 by Hilgraeve Inc. -- Monroe, MI
  4. * All rights reserved
  5. *
  6. * $Revision: 9 $
  7. * $Date: 4/24/02 3:49p $
  8. */
  9. #include <windows.h>
  10. #include <stdlib.h>
  11. #pragma hdrstop
  12. // #include <setjmp.h>
  13. #define BYTE unsigned char
  14. #include <tdll\mc.h>
  15. #include <tdll\stdtyp.h>
  16. #include <tdll\com.h>
  17. #include <tdll\assert.h>
  18. #include <tdll\session.h>
  19. #include <tdll\load_res.h>
  20. #include <tdll\xfer_msc.h>
  21. #include <tdll\file_io.h>
  22. #include <tdll\htchar.h>
  23. #include "xfr_srvc.h"
  24. #include "xfr_todo.h"
  25. #include "xfr_dsp.h"
  26. #include "xfer_tsc.h"
  27. #include "foo.h"
  28. #include "cmprs.h"
  29. #include "xfer.h"
  30. #include "xfer.hh"
  31. #include "mdmx.h"
  32. #include "mdmx.hh"
  33. #if !defined(STATIC_FUNC)
  34. #define STATIC_FUNC
  35. #endif
  36. #if !defined(CMPRS_MINSIZE)
  37. #define CMPRS_MINSIZE 4000L
  38. #endif
  39. /* * * * * * * * * * * * * * * *
  40. * local function prototypes *
  41. * * * * * * * * * * * * * * * */
  42. STATIC_FUNC int xsend_start(ST_MDMX *xc, BYTE *start_chars, int *start_char);
  43. STATIC_FUNC int getresponse(ST_MDMX *xc, int time);
  44. STATIC_FUNC void make_file_pckt(ST_MDMX *xc,
  45. struct s_mdmx_pckt *p,
  46. char *fname,
  47. long size);
  48. /* * * * * * * *
  49. * Functions *
  50. * * * * * * * */
  51. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  52. * mdmx_snd
  53. *
  54. * DESCRIPTION:
  55. * Sends a file using XMODEM or YMODEM protocol. Support 1k packets, batch
  56. * transfers and 'G' option streaming.
  57. *
  58. * ARGUMENTS:
  59. * attended -- TRUE if user is probably in attendance. Controls the display
  60. * of some messages.
  61. *
  62. * RETURNS:
  63. * True if transfer completes successfully, FALSE otherwise.
  64. */
  65. int mdmx_snd(HSESSION hSession, int attended, int method, unsigned nfiles, long nbytes)
  66. {
  67. ST_MDMX *xc;
  68. struct s_mdmx_pckt * this_pckt = NULL;
  69. struct s_mdmx_pckt * next_pckt = NULL;
  70. struct s_mdmx_pckt * tpckt;
  71. /* column values for display box */
  72. TCHAR sfname[FNAME_LEN];// file name of file being sent
  73. TCHAR xname[FNAME_LEN]; // transmitted file name
  74. int still_trying; // controls exit from main transfer loop
  75. int got_file; // controls when to complete batch op
  76. int got_response; // controls loop to get valid response
  77. int tries = 0; // number of retries for each packet
  78. unsigned total_tries; // number of retries for entire transfer
  79. int response; // response char. received from other end
  80. BYTE start_chars[3]; // acceptable start chars. from receiver
  81. int xstatus = TSC_OK; // winds up with overall status of transfer
  82. int check_type; // type of error checking in use
  83. unsigned pcktn; // number of packet currently being sent
  84. int override = FALSE; // set TRUE if comm. details changed to
  85. unsigned int uiOldOptions;
  86. int batch; // TRUE if YMODEM batch transfers used
  87. int big_pckts; // TRUE if 1K packets are allowed
  88. int streaming; // TRUE if no packet responses expected
  89. if (xfer_set_comport(hSession, TRUE, &uiOldOptions) != TRUE)
  90. {
  91. goto done;
  92. }
  93. else
  94. {
  95. override = TRUE;
  96. }
  97. /* set up options based on method used */
  98. big_pckts = (method != XF_XMODEM);
  99. batch = (method == XF_YMODEM || method == XF_YMODEM_G);
  100. streaming = FALSE; /* will be turned on if receiver starts with 'G' */
  101. // assert(nfiles == 1 || batch);
  102. this_pckt = NULL;
  103. next_pckt = NULL;
  104. xc = malloc(sizeof(ST_MDMX));
  105. if (xc == NULL)
  106. {
  107. goto done;
  108. }
  109. memset(xc, 0, sizeof(ST_MDMX));
  110. xc->hSession = hSession;
  111. xc->hCom = sessQueryComHdl(hSession);
  112. // RemoteClear(hSession);
  113. ComRcvBufrClear(xc->hCom);
  114. this_pckt = malloc(sizeof(ST_MDMX) +
  115. (big_pckts ? LARGE_PACKET : SMALL_PACKET) + 2);
  116. if (this_pckt == NULL)
  117. {
  118. goto done;
  119. }
  120. memset(this_pckt, 0, sizeof(ST_MDMX) +
  121. (big_pckts ? LARGE_PACKET : SMALL_PACKET) + 2);
  122. next_pckt = malloc(sizeof(ST_MDMX) +
  123. (big_pckts ? LARGE_PACKET : SMALL_PACKET) + 2);
  124. if (next_pckt == NULL)
  125. {
  126. goto done;
  127. }
  128. memset(next_pckt, 0, sizeof(ST_MDMX) +
  129. (big_pckts ? LARGE_PACKET : SMALL_PACKET) + 2);
  130. mdmxXferInit(xc, method); /* Could be smaller but this is easier */
  131. if (xc->p_crc_tbl == NULL)
  132. {
  133. xstatus = TSC_NO_MEM;
  134. goto done;
  135. }
  136. // hp_report_xtime(0); /* make invalid in case transfer bombs */
  137. xc->file_bytes = 0L;
  138. xc->total_bytes = 0L;
  139. xc->fh = NULL;
  140. xc->xfertimer = -1L;
  141. xc->nfiles = nfiles; /* make these available to display routines */
  142. xc->filen = 0;
  143. xc->filesize = -1L;
  144. xc->nbytes = nbytes;
  145. mdmxdspTotalsize(xc, nbytes);
  146. mdmxdspFilecnt(xc, nfiles);
  147. xc->mdmx_byte_cnt = 0;
  148. StrCharCopy(start_chars, (batch ? "CG" : "C\x15")); /* \x15 is NAK */
  149. check_type = CRC;
  150. mdmxdspChecktype(xc, (check_type == CRC) ? 0 : 1);
  151. total_tries = 0;
  152. mdmxdspErrorcnt(xc, total_tries);
  153. tries = 0;
  154. mdmxdspPacketErrorcnt(xc, tries);
  155. got_file = TRUE;
  156. while (got_file)
  157. {
  158. if ((got_file = xfer_nextfile(hSession, sfname)) == TRUE)
  159. {
  160. xc->total_bytes += xc->file_bytes;
  161. xc->file_bytes = xc->mdmx_byte_cnt = 0L;
  162. mdmxdspNewfile(xc,
  163. xc->filen + 1,
  164. sfname,
  165. sfname);
  166. ++xc->filen;
  167. if (xfer_opensendfile(hSession,
  168. &xc->fh,
  169. sfname,
  170. &xc->filesize,
  171. xname,
  172. NULL) != 0)
  173. {
  174. xstatus = TSC_CANT_OPEN;
  175. goto done;
  176. }
  177. mdmxdspFilesize(xc, xc->filesize);
  178. }
  179. else
  180. {
  181. // strblank(xname);
  182. xname[0] = TEXT('\0');
  183. }
  184. pcktn = 0;
  185. if (batch)
  186. {
  187. make_file_pckt(xc, this_pckt, xname, xc->filesize);
  188. }
  189. if ((xstatus = xsend_start(xc, start_chars, &response)) != TSC_OK)
  190. {
  191. break;
  192. }
  193. if (xc->filen <= 1)
  194. {
  195. xc->xfertimer = (long)startinterval(); /* start the clock */
  196. if (response == NAK)
  197. {
  198. check_type = CHECKSUM;
  199. }
  200. mdmxdspChecktype(xc, (check_type == CRC) ? 0 : 1);
  201. if (response == 'G')
  202. {
  203. streaming = TRUE;
  204. mdmxdspChecktype(xc, 2);
  205. }
  206. /* once we've received the first start_char,
  207. * subsequent ones must match
  208. */
  209. start_chars[0] = (BYTE)response;
  210. start_chars[1] = '\0';
  211. }
  212. if (got_file)
  213. {
  214. xc->p_getc = xm_getc;
  215. tries = 0;
  216. if (!batch &&
  217. !load_pckt(xc, this_pckt, pcktn = 1, big_pckts, check_type))
  218. {
  219. xstatus = TSC_DISK_ERROR;
  220. goto done;
  221. }
  222. }
  223. /* get the first pckt on its way while we prepare the second pckt */
  224. if ( ComSndBufrSend(xc->hCom,
  225. &this_pckt->start_char,
  226. (unsigned)this_pckt->pcktsize,
  227. SMALL_WAIT) == COM_PORT_NOT_OPEN )
  228. {
  229. xstatus = TSC_LOST_CARRIER;
  230. still_trying = FALSE;
  231. goto done;
  232. }
  233. mdmxdspPacketnumber(xc, pcktn);
  234. /* load next pckt*/
  235. if (got_file && !load_pckt(xc, next_pckt, ++pcktn, big_pckts, check_type))
  236. {
  237. xstatus = TSC_DISK_ERROR;
  238. goto done;
  239. }
  240. still_trying = TRUE;
  241. while (still_trying)
  242. {
  243. if (streaming)
  244. {
  245. /* these things are done in getresponse() if not streaming */
  246. if (xfer_carrier_lost(hSession))
  247. {
  248. xstatus = TSC_LOST_CARRIER;
  249. break;
  250. }
  251. if (xfer_user_interrupt(hSession))
  252. {
  253. xstatus = TSC_USER_CANNED;
  254. break;
  255. }
  256. }
  257. /* wait until last packet is out before watching for response */
  258. ComSndBufrWait(xc->hCom,
  259. this_pckt->pcktsize >= LARGE_PACKET ? LARGE_WAIT :
  260. SMALL_WAIT);
  261. /* get response from receiver */
  262. got_response = FALSE;
  263. while (!got_response)
  264. {
  265. response = (streaming && this_pckt->start_char != EOT) ?
  266. ACK : getresponse(xc, 60);
  267. got_response = TRUE;
  268. switch(response)
  269. {
  270. case ACK:
  271. if (this_pckt->start_char == EOT)
  272. {
  273. /* successful */
  274. mdmx_progress(xc, FILE_DONE);
  275. xc->xfertime = (long)interval(xc->xfertimer);
  276. fio_close(xc->fh);
  277. xfer_log_xfer(hSession,
  278. TRUE,
  279. sfname,
  280. NULL,
  281. TSC_OK);
  282. xc->fh = NULL;
  283. xstatus = TSC_OK;
  284. still_trying = FALSE;
  285. }
  286. else
  287. {
  288. xc->file_bytes = this_pckt->byte_count;
  289. tpckt = this_pckt;
  290. this_pckt = next_pckt;
  291. next_pckt = tpckt;
  292. /* pcktn will only be <= 1 when batch is on and
  293. * we've just sent the filename packet (packet 0)
  294. */
  295. if (pcktn <= 1 && (!got_file ||
  296. (xstatus = xsend_start(xc, start_chars, &response))
  297. != TSC_OK))
  298. {
  299. still_trying = FALSE;
  300. break;
  301. }
  302. /* send packet */
  303. if ( ComSndBufrSend(xc->hCom,
  304. &this_pckt->start_char,
  305. (unsigned)this_pckt->pcktsize,
  306. SMALL_WAIT) == COM_PORT_NOT_OPEN)
  307. {
  308. xstatus = TSC_LOST_CARRIER;
  309. still_trying = FALSE;
  310. break;
  311. }
  312. mdmxdspPacketnumber(xc, pcktn);
  313. mdmx_progress(xc, 0);
  314. if (tries != 0)
  315. {
  316. mdmxdspPacketErrorcnt(xc, 0);
  317. tries = 0;
  318. }
  319. if (this_pckt->start_char != EOT)
  320. {
  321. if (!load_pckt(xc, next_pckt, ++pcktn, big_pckts, check_type))
  322. {
  323. xstatus = TSC_DISK_ERROR;
  324. still_trying = FALSE;
  325. }
  326. }
  327. }
  328. break;
  329. case NO_RESPONSE:
  330. mdmxdspLastError(xc, 12);
  331. still_trying = FALSE;
  332. break;
  333. case ABORTED:
  334. xstatus = TSC_USER_CANNED;
  335. still_trying = FALSE;
  336. break;
  337. case CARR_LOST:
  338. xstatus = TSC_LOST_CARRIER;
  339. still_trying = FALSE;
  340. break;
  341. case 'C':
  342. case 'G':
  343. /* these act as NAKs for packets first packets */
  344. if (pcktn > 2)
  345. {
  346. got_response = FALSE;
  347. break;
  348. }
  349. /* else fall through */
  350. case NAK:
  351. if (++tries >= xc->mdmx_tries)
  352. {
  353. xstatus = TSC_ERROR_LIMIT;
  354. goto done;
  355. }
  356. else /* send packet */
  357. {
  358. if (ComSndBufrSend(xc->hCom,
  359. &this_pckt->start_char,
  360. (unsigned)this_pckt->pcktsize,
  361. SMALL_WAIT) == COM_PORT_NOT_OPEN)
  362. {
  363. xstatus = TSC_LOST_CARRIER;
  364. still_trying = FALSE;
  365. break;
  366. }
  367. }
  368. if (this_pckt->start_char == EOT && tries == 1)
  369. {
  370. break; /* don't print first retransmission on final EOT */
  371. }
  372. mdmxdspPacketErrorcnt(xc, tries);
  373. mdmxdspErrorcnt(xc, ++total_tries);
  374. mdmxdspLastError(xc,
  375. (response == NAK) ? 13 : 14);
  376. break;
  377. case CAN:
  378. if (getresponse(xc, 1) == CAN) /* two consecutive CANs? */
  379. {
  380. xstatus = TSC_RMT_CANNED;
  381. still_trying = FALSE;
  382. break;
  383. }
  384. /* fall through */
  385. default:
  386. got_response = FALSE;
  387. break;
  388. }
  389. } /* end while (!got_response) */
  390. } /* end while(still_trying) */
  391. if (!batch || xstatus != TSC_OK)
  392. {
  393. break;
  394. }
  395. } /* end while(got_file) */
  396. done:
  397. mdmx_progress(xc, TRANSFER_DONE);
  398. mdmxdspCloseDisplay(xc);
  399. // ComSendSetCharDelay(hld_send_cdelay, COMSEND_SETDELAY);
  400. if (override)
  401. {
  402. #if FALSE
  403. cnfg.bits_per_char = hld_bits_per_char;
  404. cnfg.parity_type = hld_parity_type;
  405. (void)(*ComResetPort)();
  406. #endif
  407. xfer_restore_comport(hSession, uiOldOptions);
  408. }
  409. if (xc == NULL || this_pckt == NULL || next_pckt == NULL)
  410. {
  411. xstatus = TSC_NO_MEM;
  412. }
  413. if (xc != NULL)
  414. {
  415. // hp_report_xtime((unsigned)xc->xfertime);
  416. if (xc->fh)
  417. {
  418. fio_close(xc->fh);
  419. }
  420. if (xstatus != TSC_OK)
  421. {
  422. if (xstatus != TSC_RMT_CANNED && xstatus != TSC_NO_MEM)
  423. {
  424. for (tries = 5 + 1; --tries > 0; )
  425. {
  426. ComSendChar(xc->hCom, &xc->stP, CAN);
  427. }
  428. ComSendPush(xc->hCom, &xc->stP);
  429. }
  430. xfer_log_xfer(hSession,
  431. TRUE,
  432. sfname,
  433. NULL,
  434. xstatus);
  435. }
  436. #if FALSE
  437. if (attended && xstatus != TSC_USER_CANNED && xstatus != TSC_NO_MEM)
  438. {
  439. menu_bottom_line (BL_ESC, 0L);
  440. DosBeep(beepfreq, beeplen);
  441. menu_replybox((int)xc->msgrow, ENTER_RESP, 0, (int)transfer_status_msg((unsigned short)xstatus));
  442. }
  443. #endif
  444. if (xc->p_crc_tbl != NULL)
  445. {
  446. #if defined(DEADWOOD)
  447. resFreeDataBlock(xc->hSession, xc->p_crc_tbl);
  448. xc->p_crc_tbl = NULL;
  449. #else // defined(DEADWOOD
  450. //
  451. // We don't need to free xc->p_crc_tbl since it is pointing
  452. // to a static constant array. REV: 4/10/2002
  453. //
  454. xc->p_crc_tbl = NULL;
  455. #endif // defined(DEADWOOD)
  456. }
  457. free(xc);
  458. xc = NULL;
  459. }
  460. if (this_pckt)
  461. {
  462. free(this_pckt);
  463. this_pckt = NULL;
  464. }
  465. if (next_pckt)
  466. {
  467. free(next_pckt);
  468. next_pckt = NULL;
  469. }
  470. return((unsigned)xstatus);
  471. }
  472. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  473. * xsend_start
  474. *
  475. * DESCRIPTION:
  476. * Waits up to one minute for a start request from the receiver at the
  477. * other end of the line.
  478. *
  479. * ARGUMENTS:
  480. * chktype -- Pointer to a variable to be set to the requested error
  481. * correction checking method, CRC or Checksum
  482. *
  483. * RETURNS:
  484. * Status code indicating result. Can be one of
  485. * TSC_USER_CANNED if user interrupted by hitting the ESC key.
  486. * TSC_NO_RESPONSE if 60 seconds elapses without receiving a start char.
  487. * TSC_RMT_CANNED if remote sends a control-C
  488. * TSC_OK if remote sends proper start char.
  489. *
  490. */
  491. STATIC_FUNC int xsend_start(ST_MDMX *xc, BYTE *start_chars, int *start_char)
  492. {
  493. for ( ; ; )
  494. {
  495. switch(*start_char = getresponse(xc, 60))
  496. {
  497. case ABORTED:
  498. return(TSC_USER_CANNED);
  499. case NO_RESPONSE:
  500. return(TSC_NO_RESPONSE);
  501. case CARR_LOST:
  502. return(TSC_LOST_CARRIER);
  503. case ESC:
  504. case '\003': /* control-C */
  505. return(TSC_RMT_CANNED);
  506. default:
  507. if (strchr(start_chars, *start_char))
  508. {
  509. return(TSC_OK);
  510. }
  511. /* ignore any other char. */
  512. break;
  513. }
  514. }
  515. return TSC_OK;
  516. }
  517. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  518. * getresponse
  519. *
  520. * DESCRIPTION:
  521. * Waits a specified time for a response from the receiver. Can be forced
  522. * to terminate early if user intervention is detected. No effort is made
  523. * here to interpret the meaning of a response character. Any character
  524. * received within the time limit will be returned.
  525. *
  526. * ARGUMENTS:
  527. * time -- Number of seconds to wait for a response character.
  528. *
  529. * RETURNS:
  530. * The response character if one was received or ABORTED or NO_RESPONSE or
  531. * CARR_LOST.
  532. */
  533. STATIC_FUNC int getresponse(ST_MDMX *xc, int time)
  534. {
  535. TCHAR rc = 0;
  536. long timer;
  537. DbgOutStr("getresponse ", 0,0,0,0,0);
  538. #if FALSE
  539. if (kbd_check_flagkey(xc->flagkey, TRUE) > 0)
  540. {
  541. kbd_flush();
  542. return ABORTED;
  543. }
  544. #endif
  545. if (xfer_user_interrupt(xc->hSession))
  546. {
  547. DbgOutStr("aborted\r\n", 0,0,0,0,0);
  548. return ABORTED;
  549. }
  550. // if ((rc = RemoteGet(xc->hSession)) != -1)
  551. if (mComRcvChar(xc->hCom, &rc) != 0)
  552. {
  553. DbgOutStr("returned %d\r\n", rc, 0,0,0,0);
  554. return(rc & 0x7F);
  555. }
  556. time *= 10;
  557. timer = (long)startinterval();
  558. while ((long)interval(timer) < (long)time)
  559. {
  560. #if FALSE
  561. if (kbd_check_flagkey(xc->flagkey, TRUE) > 0)
  562. {
  563. kbd_flush();
  564. return ABORTED;
  565. }
  566. #endif
  567. if (xfer_carrier_lost(xc->hSession))
  568. {
  569. DbgOutStr(" lost\r\n", 0,0,0,0,0);
  570. return CARR_LOST;
  571. }
  572. if (xfer_user_interrupt(xc->hSession))
  573. {
  574. DbgOutStr("aborted\r\n", 0,0,0,0,0);
  575. return ABORTED;
  576. }
  577. mdmx_progress(xc, 0);
  578. if (mComRcvChar(xc->hCom, &rc) != 0)
  579. {
  580. DbgOutStr("returned %d\r\n", rc, 0,0,0,0);
  581. return(rc & 0x7F);
  582. }
  583. xfer_idle(xc->hSession, XFER_IDLE_IO);
  584. }
  585. DbgOutStr(" none\r\n", 0,0,0,0,0);
  586. return(NO_RESPONSE);
  587. }
  588. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  589. * make_file_pckt
  590. *
  591. * DESCRIPTION: sets up the initial filename pckt for Ymodem (only)
  592. *
  593. * ARGUMENTS:
  594. * p -- Pointer to the packet structure which receives the filename
  595. * packet.
  596. * fname -- The file name as it should be placed in the packet.
  597. * size -- The size of the file as it should be placed in the packet.
  598. *
  599. * RETURNS:
  600. * nothing
  601. */
  602. STATIC_FUNC void make_file_pckt(ST_MDMX *xc,
  603. struct s_mdmx_pckt *p,
  604. char *fname,
  605. long size)
  606. {
  607. BYTE sizestr[20];
  608. BYTE *ptr;
  609. BYTE *cp;
  610. unsigned int crc;
  611. p->start_char = SOH; /* set start char to SOH */
  612. p->pcktnum = 0; /* set pcktnumber to 0 */
  613. p->npcktnum = 0xff; /* set npcktnumber to 0xff */
  614. ptr = p->bdata;
  615. /* initialize data area with zeros */
  616. memset(ptr, 0, SMALL_PACKET + 2);
  617. if (*fname)
  618. {
  619. StrCharCopy(ptr, fname); /* copy filename into buffer*/
  620. /* replace all back slashes with slashes */
  621. //while (strreplace(ptr, FstrBslashBslash(), "/"))
  622. // ;
  623. for (cp = ptr; *cp != '\0'; cp += 1)
  624. if (*cp == '\\') *cp = '/';
  625. // StrFmt(sizestr, "%ld", size); /* format the file size */
  626. wsprintf(sizestr, "%ld", (LONG)size);
  627. StrCharCopy(&ptr[StrCharGetByteCount(ptr)+1], sizestr);
  628. /* add it to buffer */
  629. }
  630. /* calculate CRC value */
  631. ptr = &p->bdata[SMALL_PACKET]; /* set ptr to char after buffer */
  632. /* calculate CRC */
  633. crc = calc_crc(xc, (unsigned)0, p->bdata, SMALL_PACKET+2);
  634. /* set the CRC */
  635. *ptr++ = (BYTE)(crc / 0x100);
  636. *ptr = (BYTE)(crc % 0x100);
  637. /* set the packetsize */
  638. p->pcktsize = SMALL_PACKET + 5;
  639. p->byte_count = xc->mdmx_byte_cnt;
  640. }
  641. /*********************** end of mdmx_snd.c **************************/