/* File: C:\WACKER\xfer\krm_snd.c (Created: 28-Jan-1994) * created from HAWIN source code * krm_snd.c -- Routines for handling file transmission using KERMIT * file transfer protocol. * * Copyright 1989,1990,1991,1994 by Hilgraeve Inc. -- Monroe, MI * All rights reserved * * $Revision: 5 $ * $Date: 7/11/02 11:10a $ */ // #define DEBUGSTR 1 #include #pragma hdrstop #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(BYTE) #define BYTE unsigned char #endif #include "cmprs.h" #include "itime.h" #include "xfr_dsp.h" #include "xfr_todo.h" #include "xfr_srvc.h" #include "xfer.h" #include "xfer.hh" #include "xfer_tsc.h" #include "krm.h" #include "krm.hh" // unsigned total_retries; // metachar (NEAR *p_kgetc)(void); // long kbytes_sent = 0L; // KPCKT FAR * this_kpckt; // KPCKT FAR * next_kpckt; /* local funtion prototypes */ void build_attributes(ST_KRM *kc, unsigned char *bufr, long size, unsigned long ul_time); int ksend_init(ST_KRM *kc); int ksend_break(ST_KRM *kc); int ksend_file(ST_KRM *kc, long fsize); int wldindexx(const char *string, const char FAR *substr, char wildcard, int ic); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * krm_snd * * DESCRIPTION: * send a file or files using kermit protocol * * This routine also handles logging of kermit sending operations to the * optional log file. * * ARGUMENTS: * attended -- TRUE if transfer is run manually, FALSE if run under automation * such as in host or hyperpilot * nfile -- number of files to be sent * nbytes -- total number of bytes to be sent in all files * * RETURNS: * Returns TRUE if all files are sent successfully or if all cancellations * were user-requested, 'graceful' ones. Returns FALSE if an error occurs * at either end of transfer or if user forces an immediate exit. */ int krm_snd(HSESSION hS, int attended, int nfiles, long nbytes) { ST_KRM *kc; int result; long sndsize; unsigned long filetime; long ttime; kc = malloc(sizeof(ST_KRM)); if (kc == NULL) { xferMsgClose(hS); return TSC_NO_MEM; } memset(kc, 0, sizeof(ST_KRM)); kc->hSession = hS; kc->hCom = sessQueryComHdl(hS); kc->kbytes_sent = 0L; kc->this_kpckt = NULL; kc->next_kpckt = NULL; if (kc != NULL) kc->this_kpckt = malloc(sizeof(KPCKT)); if (kc->this_kpckt != NULL) kc->next_kpckt = malloc(sizeof(KPCKT)); if (kc->next_kpckt == NULL) { if (kc->this_kpckt != NULL) { free(kc->this_kpckt); kc->this_kpckt = NULL; } if (kc != NULL) { free(kc); kc = NULL; } xferMsgClose(hS); return TSC_NO_MEM; } krmGetParameters(kc); kc->KrmProgress = ks_progress; kc->total_retries = 0; xferMsgFilecnt(kc->hSession, nfiles); xferMsgTotalsize(kc->hSession, nbytes); kc->nbytes = nbytes; kc->file_cnt = nfiles; kc->files_done = 0; kc->its_maxl = 80; kc->its_timeout = 15; kc->its_npad = 0; kc->its_padc = '\0'; kc->its_eol = kc->k_eol; kc->its_chkt = 1; kc->its_qctl = K_QCTL; kc->its_qbin = '\0'; kc->its_rept = '\0'; kc->its_capat = FALSE; kc->ksequence = 0; kc->packetnum = 1; kc->abort_code = KA_OK; kc->xfertime = -1L; if (!ksend_init(kc)) { int kret; kret = kresult_code[kc->abort_code]; free(kc->this_kpckt); kc->this_kpckt = NULL; free(kc->next_kpckt); kc->next_kpckt = NULL; free(kc); kc = NULL; xferMsgClose(hS); return(kret); } /* don't show init errors once transfer has started */ kc->total_dsp = kc->total_thru = 0L; /* new transfer starting */ while(xfer_nextfile(kc->hSession, kc->our_fname)) { // xfer_idle(kc->hSession, XFER_IDLE_IO); if (kc->abort_code == KA_LABORT1) /* TODO: figure this out */ kc->abort_code = KA_LABORTALL; if (kc->abort_code >= KA_LABORTALL) break; kc->abort_code = KA_OK; result = xfer_opensendfile(kc->hSession, &kc->fhdl, kc->our_fname, &sndsize, kc->their_fname, &filetime); if (result != 0) { kc->abort_code = KA_CANT_OPEN; break; } if (kc->its_capat) build_attributes(kc, kc->next_kpckt->pdata, sndsize, filetime); ksend_file(kc, sndsize); ++kc->files_done; if (kc->fhdl) { fio_close(kc->fhdl); kc->fhdl = NULL; } /* log transfer status here based on kc->abort_code */ xfer_log_xfer(kc->hSession, TRUE, kc->our_fname, NULL, kresult_code[kc->abort_code]); } if (kc->abort_code < KA_IMMEDIATE) ksend_break(kc); ks_progress(kc, TRANSFER_DONE); ttime = ((long)interval(kc->xfertime) / 10L); result = kresult_code[kc->abort_code]; xferMsgClose(kc->hSession); free(kc->this_kpckt); kc->this_kpckt = NULL; free(kc->next_kpckt); kc->next_kpckt = NULL; free(kc); kc = NULL; xferMsgClose(hS); return(result); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * build_attributes * * DESCRIPTION: * * ARGUMENTS: * * RETURNS: * */ void build_attributes(ST_KRM *kc, unsigned char *bufr, long size, unsigned long ul_time) { char str[15]; int sl; struct tm *pt; /* add file size in K */ wsprintf((LPSTR)str, (LPSTR)"%d", (int)(FULL_HUNKS(size, 1024))); wsprintf((LPSTR)bufr, (LPSTR)"!%c%s", tochar(sl = (int)StrCharGetByteCount(str)), (LPSTR)str); bufr += (sl + 2); /* add file size in bytes */ wsprintf((LPSTR)str, (LPSTR)"%ld", (ULONG)size); wsprintf((LPSTR)bufr, (LPSTR)"1%c%s", tochar(sl = (int)StrCharGetByteCount(str)), (LPSTR)str); bufr += (sl + 2); /* add file date and time */ ul_time += itimeGetBasetime(); /* Adjust to C7 and later */ pt = localtime((time_t*)&ul_time); assert(pt); if (pt) { /* * Dimwitted thing sometimes returns 0 */ wsprintf((LPSTR)bufr, (LPSTR)"#%c%04d%02d%02d %02d:%02d:%02d", tochar(17), pt->tm_year + 1900, pt->tm_mon + 1, pt->tm_mday, pt->tm_hour, pt->tm_min, pt->tm_sec); bufr += 19; } /* system of origin */ StrCharCat(bufr, ".\"U8"); bufr += 4; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * ksend_init * * DESCRIPTION: * * ARGUMENTS: * * RETURNS: * */ int ksend_init(ST_KRM *kc) { unsigned plen; /* length of outgoing packet data */ char rpacket[MAXPCKT]; /* space to receive response packet */ int rlen, rseq; /* length and sequence of response packet */ int tries = 0; /* set init parameters as sender */ plen = (unsigned)buildparams(kc, TRUE, kc->this_kpckt->pdata); xferMsgPacketnumber(kc->hSession, kc->packetnum); while (tries < kc->k_retries) { // xfer_idle(kc->hSession, XFER_IDLE_IO); xferMsgPacketErrcnt(kc->hSession, tries); ksend_packet(kc, 'S', plen, kc->ksequence, kc->this_kpckt); switch (krec_packet(kc, &rlen, &rseq, rpacket)) { case 'Y': if (rseq == kc->ksequence) { kc->xfertime = (long)startinterval(); getparams(kc, TRUE, rpacket); kc->ksequence = (kc->ksequence + 1) % 64; ++kc->packetnum; return(TRUE); } /* fall through */ case 'N': xferMsgLasterror(kc->hSession, KE_NAK); ++tries; break; case 'T': xferMsgLasterror(kc->hSession, KE_TIMEOUT); ++tries; break; case BAD_PACKET: if (xfer_user_interrupt(kc->hSession)) { kc->abort_code = KA_IMMEDIATE; return (FALSE); } if (xfer_carrier_lost(kc->hSession)) { kc->abort_code = KA_LOST_CARRIER; return (FALSE); } xferMsgLasterror(kc->hSession, KE_BAD_PACKET); ++tries; break; case 'E': /* received error packet, abort transfer */ xferMsgLasterror(kc->hSession, KE_RMTERR); strncpy(kc->xtra_err, rpacket, (unsigned)65); kc->abort_code = KA_RMTERR; return(FALSE); /*lint -unreachable*/ break; default: /* unexpected packet type */ kc->abort_code = KA_BAD_FORMAT; return(FALSE); /*lint -unreachable*/ break; } } /* error count has been exceeded */ kc->abort_code = KA_ERRLIMIT; return(FALSE); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * ksend_break * * DESCRIPTION: * Send 'B' packet to indicate end of transaction * * ARGUMENTS: * none * * RETURNS: * */ int ksend_break(ST_KRM *kc) { char rpacket[MAXPCKT]; /* space to receive response packet */ int rlen, rseq; /* length and sequence of response packet */ int tries = 0; while (tries < kc->k_retries) { // xfer_idle(kc->hSession, XFER_IDLE_IO); ksend_packet(kc, 'B', 0, kc->ksequence, kc->this_kpckt); switch (krec_packet(kc, &rlen, &rseq, rpacket)) { case 'Y': if (rseq == kc->ksequence) { kc->ksequence = (kc->ksequence + 1) % 64; ++kc->packetnum; return(TRUE); } /* fall through */ case 'N': case 'T': case BAD_PACKET: if (xfer_user_interrupt(kc->hSession)) { kc->abort_code = KA_IMMEDIATE; return FALSE; } if (xfer_carrier_lost(kc->hSession)) { kc->abort_code = KA_LOST_CARRIER; return FALSE; } ++tries; break; case 'E': /* received error packet, abort transfer */ StrCharCopyN(kc->xtra_err, rpacket, MAXLINE); kc->abort_code = KA_RMTERR; return(FALSE); /*lint -unreachable*/ break; default: /* unexpected packet type */ kc->abort_code = KA_BAD_FORMAT; return(FALSE); /*lint -unreachable*/ break; } } /* error count has been exceeded */ kc->abort_code = KA_ERRLIMIT; return(FALSE); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * ksend_file * * DESCRIPTION: * * ARGUMENTS: * * RETURNS: * */ int ksend_file(ST_KRM *kc, long fsize) { int tries = 0; int file_sent = FALSE; int packet_sent = FALSE; int kbd_abort = KA_OK; char rtype; int rlen, rseq; char rpacket[MAXPCKT]; int sendattr; KPCKT *tmp; DbgOutStr("ksend_file %s\r\n", (LPSTR)kc->our_fname, 0,0,0,0); xferMsgNewfile(kc->hSession, kc->files_done + 1, kc->our_fname, kc->our_fname); xferMsgFilesize(kc->hSession, fsize); xferMsgPacketErrcnt(kc->hSession, 0); xferMsgPacketnumber(kc->hSession, 0); kc->p_kgetc = ks_getc; kc->kbytes_sent = 0; /* prepare file-header packet in this_kpckt */ kc->this_kpckt->ptype = 'F'; StrCharCopyN(kc->this_kpckt->pdata, kc->their_fname, MAXPCKT); kc->this_kpckt->datalen = (int)StrCharGetByteCount(kc->this_kpckt->pdata); sendattr = kc->its_capat && (size_t)StrCharGetByteCount(kc->next_kpckt->pdata) <= (size_t)(kc->its_maxl - 5); while (!file_sent && kc->abort_code == KA_OK) /* for each packet */ { // xfer_idle(kc->hSession, XFER_IDLE_IO); tries = 0; packet_sent = FALSE; while (!packet_sent && tries++ < kc->k_retries && kc->abort_code == KA_OK) { // xfer_idle(kc->hSession, XFER_IDLE_IO); if (kbd_abort != KA_OK && tries == 1) { kc->this_kpckt->ptype = 'Z'; kc->this_kpckt->datalen = 1; StrCharCopyN(kc->this_kpckt->pdata, "D", MAXPCKT); } DbgOutStr("Calling ksend_packet %d %c (0x%x)", tries, kc->this_kpckt->ptype, kc->this_kpckt->ptype, 0,0); ksend_packet(kc, kc->this_kpckt->ptype, (unsigned)kc->this_kpckt->datalen, kc->ksequence, kc->this_kpckt); if (xfer_carrier_lost(kc->hSession)) { kc->abort_code = KA_LOST_CARRIER; break; } if (tries == 1) /* first try for this packet */ { xferMsgPacketnumber(kc->hSession, kc->packetnum); if (fsize > 0) ks_progress(kc, 0); /* get next packet ready while first is being sent */ if (sendattr) /* data alreay prepared in next_kpckt */ { kc->next_kpckt->datalen = (int)StrCharGetByteCount(kc->next_kpckt->pdata); kc->next_kpckt->ptype = 'A'; sendattr = FALSE; } else if ((kc->next_kpckt->datalen = kload_packet(kc, kc->next_kpckt->pdata)) == ERROR) { kc->next_kpckt->ptype = 'E'; kc->next_kpckt->datalen = (int)StrCharGetByteCount(kc->xtra_err); StrCharCopyN(kc->next_kpckt->pdata, kc->xtra_err, MAXPCKT); } else kc->next_kpckt->ptype = (char)(kc->next_kpckt->datalen ? 'D':'Z'); DbgOutStr(" next packet %c (0x%x)\r\n", kc->next_kpckt->ptype, kc->next_kpckt->ptype, 0,0,0); } /* end of if (tries == 1) */ else { xferMsgPacketErrcnt(kc->hSession, tries - 1); xferMsgErrorcnt(kc->hSession, ++kc->total_retries); DbgOutStr(" retry\r\n", 0,0,0,0,0); } rtype = (char)krec_packet(kc, &rlen, &rseq, rpacket); if (rtype == 'N' && (--rseq < 0 ? 63 : rseq) == kc->ksequence) rtype = 'Y'; DbgOutStr("called krec_packet %c (0x%x)\r\n", rtype, rtype, 0,0,0); switch(rtype) { case 'Y': if (rseq == kc->ksequence) { packet_sent = TRUE; kc->ksequence = (kc->ksequence + 1) % 64; ++kc->packetnum; if (kc->this_kpckt->ptype == 'A')/* response to attr pckt */ { /* If receiver responded to an attribute packet with * an 'N' in the data field, do not transfer the file. */ if (rlen > 0 && *rpacket == 'N') kbd_abort = KA_RABORT1; } if (kc->this_kpckt->ptype == 'Z')/* have we sent last one?*/ { file_sent = TRUE; kc->abort_code = kbd_abort; kbd_abort = KA_OK; } if (rlen == 1) { if (*rpacket == 'X') kbd_abort = KA_RABORT1; else if (*rpacket == 'Z') kbd_abort = KA_RABORTALL; } tmp = kc->this_kpckt; kc->this_kpckt = kc->next_kpckt; kc->next_kpckt = tmp; } else xferMsgLasterror(kc->hSession, KE_SEQUENCE); break; case 'N': xferMsgLasterror(kc->hSession, KE_NAK); break; case BAD_PACKET: xferMsgLasterror(kc->hSession, KE_BAD_PACKET); break; case 'T': xferMsgLasterror(kc->hSession, KE_TIMEOUT); break; case 'E': xferMsgLasterror(kc->hSession, KE_RMTERR); StrCharCopyN(kc->xtra_err, rpacket, MAXLINE); kc->abort_code = KA_RMTERR; return(FALSE); /*lint -unreachable*/ break; default: xferMsgLasterror(kc->hSession, KE_WRONG); kc->abort_code = KA_BAD_FORMAT; return(FALSE); /*lint -unreachable*/ break; } if (xfer_user_interrupt(kc->hSession)) { if (kbd_abort == KA_OK) /* first time */ { kbd_abort = KA_LABORT1; } else kc->abort_code = KA_IMMEDIATE; } if (xfer_carrier_lost(kc->hSession)) kc->abort_code = KA_LOST_CARRIER; } /* end while (!packet_sent && etc.) */ xferMsgPacketErrcnt(kc->hSession, tries = 0); if (kc->abort_code == KA_OK && !packet_sent) /* error count exceeded */ kc->abort_code = KA_ERRLIMIT; } /* end while (!file_sent etc.) */ xferMsgPacketnumber(kc->hSession, kc->packetnum); ks_progress(kc, FILE_DONE); kc->total_dsp += fsize; kc->total_thru += kc->kbytes_sent; kc->kbytes_sent = 0; return(file_sent); } /* end ksend_file() */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- * ks_progress * * DESCRIPTION: * Displays transfer progress indicators for Kermit Send * * ARGUMENTS: * final -- TRUE if final display for a file. * * RETURNS: * nothing */ void ks_progress(ST_KRM *kc, int status) { long ttime, stime; long bytes_sent; long cps; long krm_stime = -1; long krm_ttime = -1; long krm_cps = -1; long krm_file_so_far = -1; long krm_total_so_far = -1; if (kc->xfertime == -1L) return; ttime = (long)interval(kc->xfertime); if ((stime = ttime / 10L) != kc->displayed_time || bittest(status, FILE_DONE | TRANSFER_DONE)) { /* Display elapsed time */ krm_stime = stime; /* Display amount transferred */ bytes_sent = kc->total_dsp + kc->kbytes_sent; krm_file_so_far = kc->kbytes_sent; krm_total_so_far = bytes_sent; /* Display throughput and est. time to completion */ if ((stime > 2 || ttime > 0 && bittest(status, FILE_DONE | TRANSFER_DONE)) && (cps = ((kc->total_thru + kc->kbytes_sent) * 10L) / ttime) > 0) { krm_cps = cps; if ((kc->nbytes > 0)) { ttime = ((kc->nbytes - bytes_sent) / cps) + kc->file_cnt - kc->files_done; krm_ttime = ttime; } } kc->displayed_time = stime; } xferMsgProgress(kc->hSession, krm_stime, krm_ttime, krm_cps, krm_file_so_far, krm_total_so_far); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #define toupper(x) ((x)-'a'+'A') int wldindexx(const char *string, const char *substr, char wildcard, int ic) /* ic - ignore case */ { short index, limit; const char *s; const char *ss; if (*substr == '\0') return(0); index = 0; limit = (short)StrCharGetByteCount(string) - (short)StrCharGetByteCount(substr); while (index <= limit) { s = &string[index]; ss = substr; while (*ss == wildcard || *s == *ss || (ic && isascii(*s) && isascii(*ss) && toupper(*s) == toupper(*ss))) { ++s; if (*++ss == '\0') return(index); } ++index; } return(-1); } /********************* end of krm_snd.c ********************/