Category : C Source Code
Archive   : YMODEMC.ZIP
Filename : YMODEM.C

 
Output of file : YMODEM.C contained in archive : YMODEMC.ZIP
/*
* Copyright 1984,1985 Omen Technology Inc All Rights Reserved
* Ward Christensen Protocol handler for sending and receiving
* ascii and binary files. Modified for choice of checksum or crc.
* This code may be used for developing YMODEM support ONLY IF
* the program documentation acknowledges the origin of this code.
*/

#ifdef CPM
EXT char defdisk; /* Default disk */
EXT char origdisk; /* Disk originally logged into */
#define PSTRLEN 33 /* For misc string params */
#ifndef PATHLEN
#define PATHLEN 65 /* Plenty long */
#endif
#endif

#define CTRL(v) ('v' & 037)
#define ERROR (-1)
#define BACKUP (-3) /* Returned to expand to access prev file */
#define NOTFOUND (-4) /* Returned to expand to indicate can't open */
#define FOUNDIT (-5) /* Function found what it was looking for */
#define OK 0
#define TRUE 1
#define FALSE 0
#define SAYTERM 2 /* Doykbd returns this if sayterm needed */
#define SECSIZ 128
#define CPMEOF 0x1A

/*
* Some important usage() error numbers
*/

#define SJ_ABORT 20 /* Keyboard abort via abort key */

EXT FILE *cfin, /* Surrogate input getcty, kgets */
*fin, /* For file uploads */
*fout, /* For file downloads */
*cout, /* For text capture and utility command redirection */
*fcall; /* script reader */

EXT char cfast; /* BDS C fastest access is to extern's */
EXT char checksum; /* Delcared here for speed */
EXT unsigned oldcrc; /* Accumulates CRC checksum */
EXT int wcj, firstch, errors;
EXT int firstsec; /* First sector, C instead of NAK for crc */

#define CMDLEN 130

#define SOH 1
#define STX 2
#define ETX 3
#define EOT 4
#define ENQ 5
#define ACK 6
#define SO 016
#define SI 017
#define DLE 020
#define XON 021
#define XOFF 023
#define NAK 025
#define CAN 030
#define ESC 033
#define WANTCRC 0103 /* Send C not NAK to get crc not checksum */
#define WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */
#define TIMEOUT (-2)
#define WAICHR '\336' /* Causes a wait in put[w] and answerback */
#define RETRYMAX 10
#define RETRYNOCRC 4 /* Drop CRC request after 4 retries */
#define KSIZE 1024 /* Block length with k option */

/* Declare all globally used functions not returning int */
char *index(), *cisubstr(), *stem();
char *ascgettime(), *ascgetd(), *ascexpftime();
char **gettoken();
long fseek(), toutime(), time();
unsigned updetime();
FILE *xfopen();

This code has been modified from the Professional-YAM code with
EXT unsigned Etime; /* Elapsed time in seconds */
EXT struct tsruct calltime; /* Set when connection is made */
EXT int Zone; /* Zone in minutes from GMT */
EXT int Thiszone; /* Timezone to use for this command */

/*
* Structure passed by e1xpand to called function.
* most just use the first string part (sorry, lint!)
*/
#define UFNSIZE 68 /* 64 byte pathlen plus drive */
#define FNLENGTH 15 /* Directory filename */
#define DONOMATCH 0x8000 /* Always expand pathspecs */
struct expf {
char expfname[UFNSIZE]; /* ASCIZ file name */
long expflen; /* File length in bytes */
unsigned exptime;
unsigned expdate;
char expfn[FNLENGTH]; /* Filename only no path */
char expfattr; /* File attribute */
};


EXT char Cname[PATHLEN], Rname[PATHLEN], Tname[PATHLEN]; /* Saved filenames */

#define MAXPACK 94 /* Maximum Kermit packet size */
#define RBUFL 200 /* Kermit Receive buffer length */

/* Some declarations for USQ feature */
#define SQMAGIC 0xFF76 /* SQueezed file prefix */
#define KSQMAGIC 0xFF75 /* Cipher key magic word */
#define KEYSIZE 4096 /* Max size of key file */
#define NUMVALS 257 /* 256 data values plus SPEOF*/

extern union { /* Decoding tree for usq feature */
struct {
char ffxpkt[MAXPACK+8]; /* Far fetch MUST BE FIRST */
char rxpkt[RBUFL+2]; /* Receive packet buffer */
char txpkt[MAXPACK+8]; /* Packet buffer */
char sxpkt[MAXPACK+8]; /* Server command buffer */
char dxpkt[MAXPACK+8]; /* Packet buffer */
char axbuf[CMDLEN+2]; /* For CB command, etc. */
char kfilnam[PATHLEN+2];
} k;
char ubuf[KSIZE+2];
struct {
int children[2]; /* Left, Right */
} dnode[NUMVALS - 1];
} U;

EXT FLAG Key; /* True iff unsqueezing encrypted file */



expanations added for support routines not included.

#include "yamsys.h" /* Installation specific stuff */
#include "yam.h"
#define WCEOT (-10)

long Modtime; /* Unix style mod time for incoming file */
int Usemtime; /* <>0: Accept file mod time */
int Filemode; /* Unix style mode for incoming file */
char rxcmdchar; /* NAK, C, or G to specify rx mode */
extern char *Rcmdlog; /* Remote commands logged to this file */
static FLAG eotseen; /* <>0 if an EOT has been seen for this rx packet */

wcsend(argc, argp)
char **argp;
{
int wcs();

Crcflg = FALSE;
firstsec = TRUE;
if (Batch) {
lhmargin();
printf("Sending in Batch Mode\n");
/* Expand calls the specified function once for each file, with that
pathname as argument */
if (expand(wcs, argc, argp, 0) == ERROR)
goto fubar;
if (wctxpn("") == ERROR)
goto fubar;
}
else {
for (; --argc>=0;) {
/* Opentx opens a file for sending - `ala fopen(name, "rb" .. */
if (opentx(*argp++) == ERROR)
goto fubar;
if (wctx() == ERROR)
goto fubar;
}
}
return OK;
fubar:
closetx('E'); ++Errcnt;
canit();
return ERROR;
}

wcs(ufn)
register struct expf *ufn;
{
if (opentx(ufn->expfname) == ERROR)
return OK; /* skip over inaccessible files */
if (wctxpn(ufn) == ERROR)
return ERROR;
if (wctx() == ERROR)
return ERROR;
return OK;
}


wcreceive(argc, argp)
char **argp;
{
rxcmdchar = NAK;
if (Batch || argc == 0)
Crcflg = Batch = TRUE;
if (Crcflg)
rxcmdchar = WANTCRC;
if (Optiong > 0)
Crcflg = rxcmdchar = WANTG;

if (Batch) {
lhmargin(); Batch = TRUE;
printf("Receiving in Batch Mode\n");
if (argc)
usage(11);
for (;;) {
if (wcrxpn(U.ubuf)== ERROR)
goto fubar;
if (U.ubuf[0] == 0) {
pstat(""); return OK;
}
procheader(U.ubuf);

if (wcrx(U.ubuf) == ERROR)
goto fubar;
}
}
else {
procheader(NULL);
if (Xmodem)
printf("Receive:'%s' FILE OPEN\n", *argp);
if (wcrx(*argp) == ERROR)
goto fubar;
}
Bytesleft = DEFBYTL; return OK;
fubar:
Bytesleft = DEFBYTL; canit(); closerx(eotseen?'Q':ERROR);
++Errcnt; return ERROR;
}

/*
* Fetch a pathname from the other end as a C ctyle ASCIZ string.
* Length is indeterminate as long as less than blklen
* a null string represents no more files
*/
wcrxpn(rpn)
char *rpn; /* receive a pathname */
{
purgeline();
Crcflg = firstsec = TRUE;
lpstat("Fetching pathname");
totsecs = -1;
if (wcgetsec(rpn, rxcmdchar) != 0)
return ERROR;
/* Send the ACK unless g option */
if (Optiong <= 0)
sendline(ACK);
FLUSHMO;
return OK;
}

wctxpn(ufn)
struct expf *ufn;
{
register char *p, *q;
int i;
#ifdef MTIME
long mdt; struct dstruct d; struct tsruct t;
#endif
totsecs = -1;
pstat("Awaiting pathname NAK");
if (getnak())
return ERROR;
for (i = KSIZE, q = U.ubuf; --i >= 0; )
*q++ = 0;
p = ufn->expfname;
if (*p) {
#ifdef MTIME
tdexpftime(&d, &t, ufn);
mdt = toutime(&d, &t) + Thiszone*60L;
#endif
if (!Fullpath) {
p = stem(p);
uncaps(p);
}
for(q = U.ubuf; *p; ) /* don't send drive: */
if((*q++ = *p++) == ':')
q = U.ubuf;
/* transmit file length */
#ifdef MTIME
sprintf(++q, "%ld %lo 0 %ld", ufn->expflen, mdt, Serialn);
#else
sprintf(++q, "%ld 0 0 %ld", ufn->expflen, Serialn);
#endif
}

if (wcputsec(U.ubuf, 0, SECSIZ) == ERROR) {
wcperr("Can't send pathname %s", p);
return ERROR;
}
return OK;
}

getnak()
{
register c;

Lastrx = 0;
for (;;) {
FLUSHMO;
switch (firstch = readline(400)) {
case TIMEOUT:
return TRUE;
case WANTG:
Optiong = 1; blklen = 1024;
/* **** FALL THRU TO **** */
case WANTCRC:
Crcflg = TRUE;
/* **** FALL THRU TO **** */
case NAK:
if ((c=readl0()) == TIMEOUT)
return FALSE;
if (c == 'K') { /* IMP hack */
blklen = 1024; return FALSE;
}
/* **** FALL THRU TO **** */
case CAN:
if (Lastrx == CAN)
return TRUE;
/* **** FALL THRU TO **** */
default:
showctl(firstch);
}
Lastrx = firstch;
}
}

/*
* Adapted from CMODEM13.C, written by
* Jack M. Wierda and Roderick W. Hart
*/

wcrx(name)
char *name;
{
register char *p;
register cblklen; /* bytes to dump this block */
int sendchar, sectnum, sectcurr;
int syntry; /* number of tries to get right sec */

if (openrx(name) == ERROR)
return ERROR;
firstsec = TRUE; eotseen = FALSE; totsecs = sectnum = 0;
sendchar = rxcmdchar;

for (;;) {
syntry = 0; /* # of tries for right sector */
synagain:
sectcurr = wcgetsec(U.ubuf, sendchar);
if (sectcurr == (sectnum+1 & 0377)) {
sectnum++;
/*
* if the compiler supports longs && the o/s records the
* exact length of files then and only then use the file length
* info (if transmitted).
*/
wcj = cblklen = Bytesleft>blklen ? blklen:Bytesleft;

Charsrx += wcj;
if (Overlapio) {
if (Optiong <= 0)
sendline(ACK);
sendchar = -1;
} else
sendchar=ACK;
FLUSHMO;
for (p = U.ubuf; --wcj>=0; )
if (putc(*p++, fout) == ERROR)
usage(30);
if (View) {
wcj = cblklen;
for (p = U.ubuf;--wcj>=0;)
bttyout(*p++);
}
if ((Bytesleft -= cblklen) < 0)
Bytesleft = 0;
totsecs += blklen/128;
}
else if (sectcurr == (sectnum & 0377)) {
wcperr("Received dup Sector");
sendchar = ACK;
}
else if (sectcurr == WCEOT) {
sendline(ACK);
FLUSHMO;
/* Don't pad the file any more than it already is */
closerx('R');
#ifdef MTIME
if (Modtime) {
sutime(Rname, Modtime - Thiszone*60L);
Modtime = 0L;
}
#endif
return OK;
}
else if (sectcurr == ERROR)
return ERROR;
else {
wcperr("Sync Error: got %d", sectcurr);
if (++syntry < 12) {
sendchar = Batch ? WANTCRC : NAK;
goto synagain;
}
return ERROR;
}
}
}

/*
* wcgetsec fetches a Ward Christensen type sector.
* Returns:
* sector number encountered
* or ERROR if valid sector not received, or CAN CAN received
* or WCEOT if eot sector
***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
* (Caller must do that when he is good and ready to get next sector)
*/

wcgetsec(rxbuf, sendchar)
char *rxbuf;
{
register char *p;
register c;
register sectcurr;
register maxtim = 100;

eotseen = FALSE;
for (Lastrx = errors = 0; errors < RETRYMAX; ++errors, ++toterrs) {
if(Ctrlbrk)
return ERROR;

if (firstsec && !Batch && errors >= RETRYNOCRC ) {
sendchar = NAK; Crcflg = FALSE;
}
showsec();
if (sendchar > 0) {
sendline(sendchar); /* Send it now, we're ready! */
}
FLUSHMO;
blklen = SECSIZ;
noisereject:
switch (c = readline(maxtim)) {
case CAN:
if (Lastrx == CAN) {
wcperr("Sender CANcelled");
return ERROR;
} else {
Lastrx = CAN;
continue;
}
case EOT:
if (Optiong)
return WCEOT;
++eotseen;
/* make sure eot really is eot and not just mixmash */
if (readl0() == TIMEOUT) {
if (!Crcflg || Lastrx == EOT)
return WCEOT;
Lastrx = EOT; goto bilge3;
}
goto bilge;
case STX:
blklen = KSIZE;
case SOH:
sectcurr = readline(50);
if ((sectcurr+readline(50)) == 0377) {
checksum = oldcrc = 0;
for (p = rxbuf,wcj = blklen; --wcj>=0; ) {
if ((c = readline(50)) < 0)
goto bilge;
oldcrc = updcrc(c, oldcrc);
checksum += (*p++ = c);
}
if ((c = readline(50)) < 0)
goto bilge;
if (Crcflg) {
oldcrc = updcrc(c, oldcrc);
if ((c = readline(50)) < 0)
goto bilge;
oldcrc = updcrc(c, oldcrc);
if (oldcrc) {
wcperr("Bad CRC=%04x",
oldcrc);
goto bilge2;
}
else {
firstsec = FALSE;
return sectcurr;
}
}
else if ((checksum-c) & 0377) {
wcperr("Checksum Bad rx=%02x cx=%02x",
c, checksum);
goto bilge2;
} else {
firstsec = FALSE;
return sectcurr;
}
}
wcperr("Sector number garbled"); goto bilge;
default:
if (Crcflg)
goto noisereject;
case TIMEOUT:
break;
}
bilge:
switch (c) {
case TIMEOUT:
wcperr("Timeout"); goto bilge3;
case ERROR: case (ERROR & ~0200):
Mcstat = 0;
wcperr("Modem SR=%02x", Mcstat);
break;
default:
wcperr("Got %02x sector header", c);
break;
}
bilge2:
junkpacket();
bilge3:
if (firstsec)
sendchar = rxcmdchar;
else {
maxtim = 50;
sendchar = NAK;
}
}
/* try to stop the bubble machine. */
canit(); return ERROR;
}

/*VARARGS1*/
wcperr(s,p,q)
char *s, *p, *q;
{
char bufx[70];

llhmargin();
sprintf(bufx, s, p, q);
lprintf("Sector %3d error %d: %s\n", totsecs, errors, bufx);
#ifdef DEBUG2
if ( !Serialn) {
logfile(Rcmdlog, bufx, firstch, (long)totsecs);
if (Xmodem && !carrier())
logfile(Rcmdlog, "CARRIER LOST", 'C', (long)updetime());
}
#endif
}

showsec()
{
if (!Quiet)
pstat("Sector %3d %2dk %s",
totsecs, totsecs/8, Crcflg?"CRC-16":"" );
}

wctx()
{
register char *p;
register unsigned sectnum;

firstsec = TRUE; totsecs = 0;
pstat("Awaiting initial NAK");

if (getnak())
return ERROR;
sectnum = 1;
while (filbuf(U.ubuf, blklen)) {
totsecs += (blklen/128);
showsec();
if (wcputsec(U.ubuf, sectnum, blklen) == ERROR) {
#ifdef DEBUG2
if ( !Serialn)
logfile(Rcmdlog, "SE1", firstch, Charstx);
#endif
if (firstch == WANTCRC && sectnum > 1) {
long lseek();

if (lseek(fileno(fin), -blklen*2L, 1) == -1L)
return ERROR;
--sectnum; Charstx -= blklen;
totsecs -= (blklen/64);
wcperr("Resynchronizing");
continue;
}
return ERROR;
} else {
if (View)
for (p = U.ubuf,wcj = blklen;--wcj>=0;)
bttyout(*p++);
++sectnum; Charstx += blklen;
}
}
closetx('S');
for (errors = 0; ++errors purgeline();
sendline(EOT);
FLUSHMO;
if (Ctrlbrk)
break;
if((firstch=readline(100)) == ACK || firstch == (ACK|0200))
return OK;
wcperr("Got %02x for ACK to EOT", firstch);
}
wcperr("No ACK on EOT");
return ERROR;
}

wcputsec(txbuf, sectnum, cseclen)
char *txbuf;
register unsigned sectnum;
int cseclen; /* data length of this sector to send */
{
register char *p;
FLAG nogood;

firstch = 0; /* part of logic to detect CAN CAN */

for (errors = 0; errors < RETRYMAX; ++errors, ++toterrs) {
nogood = FALSE;
if (Ctrlbrk)
goto cancan;
Lastrx = firstch;
sendline(cseclen == KSIZE?STX:SOH);
sendline(sectnum);
sendline(-sectnum-1);
oldcrc = checksum = 0;
for (wcj = cseclen,p = txbuf; --wcj>=0; ) {
sendline(*p);
oldcrc = updcrc(*p, oldcrc);
checksum += *p++;
if (miinqueue()) {
switch (michar()) {
case CAN:
goto chkcan;
case XOFF:
readline(500); break;
default:
break;
}
}
}
if (Crcflg) {
oldcrc = updcrc(0,updcrc(0,oldcrc));
sendline(oldcrc>>8);sendline(oldcrc);
}
else
sendline(checksum);
if (Ctrlbrk)
goto cancan;

if (miready()) {
wcperr("Noise Burst Detected");
if (Optiong > 0)
goto cancan;
nogood = TRUE; purgeline();
}
if (Optiong) {
firstsec = FALSE; return OK;
}
FLUSHMO;
firstch = readline(400);
gotnak:
switch (firstch) {
case CAN:
chkcan:
if(Lastrx == CAN) {
cancan:
wcperr("Receiver Cancelled"); return ERROR;
}
break;
case TIMEOUT:
wcperr("Timeout on sector ACK"); continue;
case WANTCRC:
if (firstsec)
Crcflg = TRUE;
case NAK:
wcperr("NAK on sector");
#ifdef NOTDEF
/* ******* TESTING ********** */
{
extern Quitafter;
if (Quitafter && Verbose) {
wcperr("Faking ACK: ALT-Q");
Quitafter = FALSE; return OK;
}
}
#endif
continue;
case ACK:
gotack:
if (nogood)
break;
if (!Tfile || (sectnum==0) || (readl0()==TIMEOUT)) {
firstsec = FALSE; return OK;
}
wcperr("Got burst for sector ACK");
break;
case ACK|0200:
if ( !Tfile)
goto gotack;
default:
wcperr("Got %02x for sector ACK", firstch); break;
}
for (;;) {
Mcstat = 0;
Lastrx = firstch;
if ((firstch = readline(400)) == TIMEOUT)
break;
if ((firstch == NAK || firstch == WANTCRC)
&& readl0() == TIMEOUT)
goto gotnak;
if (firstch == CAN && Lastrx == CAN)
goto cancan;
/* Let user see it if strange char */
showctl(firstch);
}
}
wcperr("No ACK on sector");
return ERROR;
}

/* Throw away incoming packet */
junkpacket()
{
register n = 3600;
register c;
register b;

b = Ctrlbrk; Ctrlbrk = 0;
pstat("%sError Recovery", Outarev);
while (--n) {
if (cdo()) {
prcdo(); goto done;
}
switch (c = readline(20)) {
case TIMEOUT:
goto done;
case CAN:
case ETX:
if (c == readline(10)) {
b=c; goto done;
}
}
}
done: Ctrlbrk |= b; Mcstat = 0;
pstat("");
}


/*
* Send 5 CAN's to try to get the other end to shut up
* then 5 backspaces to edit out the CAN's
*/
canit()
{
register c;

junkpacket();
for (c = 5; --c>=0; )
sendline(CAN);
for (c = 5; --c>=0; )
sendline('\b');
FLUSHMO;
}

/* Fill buf with count chars padding with ^Z for CPM */
filbuf(buf, count)
char *buf;
{
register m;

#ifdef NOTDEF
register c;
m = count;
while((c=getc(fin))!=EOF) {
*buf++ =c;
if(--m == 0)
break;
}
if(m == count)
return 0;
else
while(--m >= 0)
*buf++ = 032;
return count;
#else
m = read(fileno(fin), buf, count);
if (m <= 0)
return 0;
while (m < count)
buf[m++] = 032;
return count;
#endif
}


/*
* Process incoming header
*/
procheader(name)
register char *name;
{
register char *p;
long theirsn;
extern char Instmsg[];

/* set default parameters */
Bytesleft = DEFBYTL; Filemode = 0666; Modtime = 0L;

if (name) {
p = name + 1 + strlen(name);
if (*p) { /* file coming from Unix type system */
sscanf(p, "%ld%lo%o%lo", &Bytesleft,
&Modtime, &Filemode, &theirsn);
#ifndef DEMO
if (Serialn && theirsn == Serialn) {
Instmsg[0] = 0; usage(26);
}
#endif
}
}
}

/*
* Routines to convert to/from Unix(TM) 32 bit time code (epoch:1970).
* Good for times 1970 to 2035 approximately, by which time we should
* be timestamping files in microseconds since the Big Bang ...
*
* Original factor routine from Lynn Long
*/

#define EPOCH 719542L

long int factor(mm, dd, yy)
long int mm, dd, yy;
{
long int raw;

raw = 365 * yy + dd -1 + 31 * (mm - 1);
if(mm < 3)
raw += ((yy -1)/4);
else
raw -= (23 + 4*mm)/10L - yy/4;
return(raw);
}

#ifdef MTIME


struct dstruct { /* Structure filled in by msdate() */
int year;
char month;
char day;
};
struct tsruct { /* Structure filled in by mstod() */
char hrs;
char mins;
char secs;
char csecs;
};

static dayinmo[]= { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

#define DAYSEC 86400L
#define DAYPYR(y) (((y&03)) ? 365:366)
/*
* Unpacks Unix format time into dstruct and tsruct structures
*/

unutime(ds, ts, t)
register struct dstruct *ds;
register struct tsruct *ts;
long t;
{
register int c;
register long days, rem, y, mo;

rem = t % DAYSEC; days = t / DAYSEC;
ts->csecs = 0;
ts->secs = rem % 60L; rem /= 60L;
ts->mins = rem % 60L; ts->hrs = rem/60L;

for (y=1970; days>=(c=DAYPYR(y)); ++y)
days -= c;

dayinmo[1] = c==366 ? 29:28;

for (mo=0; days>=(c=dayinmo[mo]); ++mo)
days -= c;

ds->day = days+1; ds->month = mo+1; ds->year = y - 1980;
#ifdef DEBUG
lprintf("Unutime: da %d mo %d yr %d %d:%d:%d\n",
ds->day, ds->month, ds->year, ts->hrs, ts->mins, ts->secs);
#endif
}


/*
* Packs dstruct and tsruct structures into Unix format time
*/

long
toutime(ds, ts)
register struct dstruct *ds;
register struct tsruct *ts;
{
register long t;

t = factor((long)ds->month, (long)ds->day, ds->year + 1980L);
t -= EPOCH; t *= DAYSEC;
t += ts->secs; t += ts->mins*60; t += ts->hrs*3600L;
#ifdef DEBUG
lprintf("Toutime: da %d mo %d yr %d %d:%d:%d %lo\n",
ds->day, ds->month, ds->year, ts->hrs, ts->mins, ts->secs, t);
#endif
return t;
}

/*
* Sets file s to Unix time t
*/
sutime(s, ti)
char *s;
long ti;
{
struct dstruct ds;
struct tsruct ts;
register unsigned d, t;

unutime(&ds, &ts, ti);

d = ds.day + (ds.month << 5) + (ds.year << 9);
t = (ts.secs >> 1) + (ts.mins << 5) + (ts.hrs << 11);
#ifdef DEBUG
lprintf("Sutime: d=%x t=%x", d, t);
lprintf(" da %d mo %d yr %d %d:%d:%d\n",
ds.day, ds.month, ds.year, ts.hrs, ts.mins, ts.secs);
#endif
if (Usemtime)
utime(s, d, t);
}

/*
* Unpack time from struct expf to tsruct and dstruct
*/
tdexpftime(ds, ts, e)
register struct expf *e;
register struct dstruct *ds;
register struct tsruct *ts;
{
ts->hrs = (e->exptime>>11);
ts->mins = ((e->exptime>>5)&077);
ts->secs = ((e->exptime&037)<<1);
ds->month = ((e->expdate>>5)&017);
ds->day = (e->expdate&037);
ds->year = ((e->expdate>>9)%100);
#ifdef DEBUG
lprintf("TDEX.. da %d mo %d yr %d %d:%d:%d\n",
ds->day, ds->month, ds->year, ts->hrs, ts->mins, ts->secs);
#endif
}

#endif /* M T I M E */


  3 Responses to “Category : C Source Code
Archive   : YMODEMC.ZIP
Filename : YMODEM.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/