Category : Recently Uploaded Files
Archive   : MSQ320.ZIP
Filename : MSG.C

 
Output of file : MSG.C contained in archive : MSQ320.ZIP
/* msg.c

released into the PUBLIC DOMAIN 10 jul 1994 by John Dennis

NOTE:
Because the SDM routines are NOT the same (the Msgn are the same as
the UIDs, so the Msgn's are not contiguous), I basically had to create
my own API to distance my code from the real API. (Making it easy to
integrate other message types). All msgbase specific stuff should be
kept within the module that handles it.

*/

#define NO_STDLIB /* causes conflicts with errno.h in MSC */
#define DEBUG 0

#include
#include
#include "msged.h"
#include "date.h"
#include
#include
#include
#include
#ifdef __MSC__
#include
#endif
#include
#include
#if DEBUG
#include
#endif

#define CHUNKSZ 10 /* size of chunk to allocate as extra */

/* ------------------------------------------------------------------*/
/* prototypes */
/*-------------------------------------------------------------------*/

#include "normal.h"

static time_t stampToTimeT(struct _stamp *st);
static struct _stamp *timeTToStamp(time_t);

/* ------------------------------------------------------------------*/
/* typedefs and global vars */
/*-------------------------------------------------------------------*/

extern struct _minf minf;
extern word _stdc msgapierr;

MSG *Ahandle = NULL; /* area handle */
static MSGH *mh = NULL; /* message handle */
static XMSG xmsg; /* squish message header */

char msgbuf[BUFLEN]; /* message text buffer */
char cinfbuf[BUFLEN]; /* control info buffer */

static UMSGID replyto = 0; /* to ensure correct uplinks when $mxx is used */

static unsigned long num_msgs, /* number of messages in msgbase */
new = 0; /* if msg being written is new */


/*-------------------------------------------------------------------*/
/* */
/* open_sqbase(char *path); */
/* */
/* opens the msgbase at path, creating if it doesn't exist. */
/* */
/*-------------------------------------------------------------------*/

int open_sqbase(char *path, word type)
{
#if DEBUG
assert(mh==NULL);
#endif
if (mh != NULL) { /* if we didn't close it for whatever reason... */
MsgCloseMsg(mh);
mh = NULL;
}
#if DEBUG
assert(Ahandle==NULL);
#endif
if (Ahandle != NULL) { /* if we didn't close it for whatever reason... */
if (MsgCloseArea(Ahandle) == -1) {
return (-1); /* urg, this should *not* happen */
}
}
if ((Ahandle=MsgOpenArea((unsigned char *)path,
MSGAREA_CRIFNEC,
type))==NULL) {
return (-1); /* create if not already there */
}
return TRUE;
}



/*-------------------------------------------------------------------*/
/* */
/* squish_scan(AREA *a); */
/* */
/* scans an area for messages, opening the msgbase and filling */
/* the message[] array. */
/* */
/*-------------------------------------------------------------------*/

long SquishMsgAreaOpen(AREA *a)
{
struct stat b; /* stats for sql file */
unsigned long lastread; /* lastread record */
char work[256]; /* path to sql file */
int sql; /* file handle */
unsigned long k = 0; /* counter */

a->last = a->first = 1;
a->lastread = a->current = 1;

a->status = 0; /* not open currently */

if (a->msgtype == FIDO) /* open the msgbase */
{
if (open_sqbase(a->path, MSGTYPE_SDM) == -1)
{
return 0;
}
}
else
if (open_sqbase(a->path, MSGTYPE_SQUISH) == -1)
return 0;

sprintf(work,"%s.SQL", a->path);
sql = sopen(work, O_BINARY|O_RDWR, SH_DENYNO, S_IWRITE|S_IREAD);
if (sql != -1)
{
fstat(sql, &b);
/* we make it big enough */
if (b.st_size < (SW->useroffset * sizeof(long)))
{
lastread = 0;
k = b.st_size / sizeof(long);
lseek(sql, 0L, SEEK_END);
while (SW->useroffset > k) {
write(sql, &lastread, sizeof(long));
k++;
}
}
else
{ /* we read the data in */
lseek(sql, SW->useroffset * sizeof(long), SEEK_SET);
if (read(sql, &lastread, sizeof(UMSGID)) == sizeof(long))
{
if (CurArea.netmail)
a->lastread = a->current = MsgUidToMsgn(Ahandle, lastread, UID_PREV);
else
a->lastread = a->current = MsgUidToMsgn(Ahandle, lastread, UID_NEXT);
}

}
close(sql);
}

a->last = MsgHighMsg(Ahandle);
a->status = 1;

if (a->last >= 1 && a->current == 0)
{
a->lastread = 1;
a->current = 1;
}

return a->last;
}



/*-------------------------------------------------------------------*/
/* */
/* squish_readheader(unsigned long n); */
/* */
/* reads in the message header and control info for the message. */
/* */
/*-------------------------------------------------------------------*/

msg *SquishMsgReadHeader(unsigned long n, int type)
{
char path[PATHLEN];
msg *m;
int i = 0;

#if DEBUG
assert(mh==NULL);
assert(Ahandle!=NULL);
#endif

if (!Ahandle)
{
return NULL;
}

if (mh != NULL) /* if open, close it */
{
MsgCloseMsg(mh);
}
/* open msg we want to open */
if ((mh=MsgOpenMsg(Ahandle, MOPEN_READ, n)) == NULL)
{
return NULL;
}

if (MsgReadMsg(mh, &xmsg, 0L, 0L, NULL, BUFLEN,
(unsigned char *)cinfbuf) == (dword)-1)
{
MsgCloseMsg(mh); /* no message header or control info! */
mh = NULL;
return NULL;
}

if ((m = (msg *) calloc(1, sizeof(msg))) == NULL)
{
outamemory();
}
/* basically copy info across to msg */
m->msgnum = MsgMsgnToUid(Ahandle, n);
m->from.zone = xmsg.orig.zone;
m->from.net = xmsg.orig.net;
m->from.node = xmsg.orig.node;
m->from.point = xmsg.orig.point;

m->to.zone = xmsg.dest.zone;
m->to.net = xmsg.dest.net;
m->to.node = xmsg.dest.node;
m->to.point = xmsg.dest.point;

m->from.domain = NULL;
m->to.domain = NULL;

if (xmsg.date_written.date.yr != 0)
{
m->timestamp = stampToTimeT(&xmsg.date_written);
m->time_arvd = stampToTimeT(&xmsg.date_arrived);
}
else /* only use this when necesary */
{
memset(path, 0, sizeof path);
memcpy(path, xmsg.__ftsc_date ,sizeof xmsg.__ftsc_date);
m->timestamp = parsedate(path);
}

if ((m->isto = (char *) calloc(1,sizeof xmsg.to + 1)) == NULL) outamemory();
if ((m->isfrom = (char *) calloc(1,sizeof xmsg.from + 1)) == NULL) outamemory();
if ((m->subj = (char *) calloc(1,sizeof xmsg.subj + 1)) == NULL) outamemory();

memcpy(m->isto, xmsg.to, sizeof xmsg.to);
memcpy(m->isfrom, xmsg.from, sizeof xmsg.from);
memcpy(m->subj, xmsg.subj, sizeof xmsg.subj);

m->attrib.private = (xmsg.attr & MSGPRIVATE) != 0;
m->attrib.crash = (xmsg.attr & MSGCRASH) != 0;
m->attrib.recvd = (xmsg.attr & MSGREAD) != 0;
m->attrib.sent = (xmsg.attr & MSGSENT) != 0;
m->attrib.attached = (xmsg.attr & MSGFILE) != 0;
m->attrib.forward = (xmsg.attr & MSGFWD) != 0;
m->attrib.orphan = (xmsg.attr & MSGORPHAN) != 0;
m->attrib.killsent = (xmsg.attr & MSGKILL) != 0;
m->attrib.local = (xmsg.attr & MSGLOCAL) != 0;
m->attrib.hold = (xmsg.attr & MSGHOLD) != 0;
m->attrib.direct = (xmsg.attr & MSGXX2) != 0;
m->attrib.freq = (xmsg.attr & MSGFRQ) != 0;
m->attrib.rreq = (xmsg.attr & MSGRRQ) != 0;
m->attrib.rcpt = (xmsg.attr & MSGCPT) != 0;
m->attrib.areq = (xmsg.attr & MSGARQ) != 0;
m->attrib.ureq = (xmsg.attr & MSGURQ) != 0;

if (xmsg.attr & MSGSCANNED) /*?*/
m->scanned = 1;

m->replyto = MsgUidToMsgn(Ahandle, xmsg.replyto, UID_EXACT);

while (i < 9)
{
if (xmsg.replies[i] != 0)
{
m->replies[i] = MsgUidToMsgn(Ahandle, xmsg.replies[i], UID_EXACT);
}
else
{
m->replies[i] = 0;
}
i++;
}
m->replies[9] = 0;

m->cost = 0;
m->times_read = 0;
m->text = NULL;
m->to.fidonet = m->from.fidonet = 1;

if (type == RD_HEADER)
{
MsgCloseMsg(mh);
mh = NULL;
}
return m;
}



/*-------------------------------------------------------------------*/
/* */
/* squish_readtext(unsigned long n); */
/* */
/* reads in the entire message, adds the control info to the */
/* beginning of the message and continues to return the message */
/* to the caller line by line (at each subsequent call). */
/* basically a conversion of the corresponding fido funtion. */
/* */
/*-------------------------------------------------------------------*/

char *SquishMsgReadText(unsigned long n)
{
static char *next = NULL;
static char *end = NULL;
char *t = NULL;
char *text = NULL;
char eol = '\0';
unsigned long i, l;
static unsigned long ofs = 0, s = 0;

#if DEBUG
assert(Ahandle!=NULL);
assert(n>0);
assert(mh!=NULL);
#else
unused(n);
#endif

if (!Ahandle)
{
return NULL;
}

if (next == NULL && s != 0) /* we are finished */
{
s = ofs = 0;
return NULL;
}
if (s == 0) /* ready to read in new msg */
{
memset(msgbuf, 0, BUFLEN-1);
next = msgbuf;
if (MsgGetCtrlLen(mh) > 0) /* copy control info from */
{
t = cinfbuf; /* insert /r's */
*(t + (size_t)MsgGetCtrlLen(mh)) = '\0';
if (*t != '\0')
{
*next++ = *t++;
while (*t != '\0')
{
if (*t == '\01')
{
*next++ = '\r'; /* add a \r to the text */
}
*next++ = *t++;
}
if (*(next - 1) == '\01')
{
next--;
*(next) = '\0';
}
else
{
*next++ = '\r';
*next = '\0'; /* terminate string */
}
}
next = msgbuf;
end = msgbuf + strlen(msgbuf);
normalize(msgbuf);
}
else
next = NULL;

s = BUFLEN;
} /* return msg a line at a */
/* time */
if (next == NULL)
{
i = MsgReadMsg(mh, NULL, ofs, s - 1,
(unsigned char *)msgbuf, 0L, NULL);
ofs += i;
if (i < 1)
{
s = ofs = 0;
next = NULL;
return NULL;
}
next = msgbuf;
while (i && (*next == '\0'))
{
i--; next++;
}
normalize(next);
end = msgbuf + strlen(msgbuf);
if (end < next)
next = end;
}

if ((end - next) == 0) t = NULL;
else t = memchr(next,'\n',(int) (end - next));

if (t == NULL) {
l = strlen(next);
memmove(msgbuf, next, (size_t)(l+1));
i = MsgReadMsg(mh, NULL, ofs, s - l - 1,
(unsigned char *)(msgbuf + (size_t)l), 0L, NULL);
ofs += i;
if (i < 1)
{
next = NULL;
return(strdup(msgbuf));
}
*(msgbuf + (size_t)l + (size_t)i) = '\0';
normalize(msgbuf+(size_t)l);
end = msgbuf + strlen(msgbuf);
next = msgbuf;
t = strchr(next, '\n');
}

if (t != NULL)
{
eol = *(t+1);
*(t+1) = '\0';
}

text = strdup(next);

if (t != NULL)
{
*(t+1) = eol;
next = t+1;
}
else
next = NULL;

return text;
}


/*-------------------------------------------------------------------*/
/* */
/* squish_writeheader(msg *m); */
/* */
/* writes msg header to the msgbase, creates new frame if new msg, */
/* and makes sure links are correct. */
/* */
/*-------------------------------------------------------------------*/

int SquishMsgWriteHeader(msg *m, int type)
{
unsigned long n = MsgUidToMsgn(Ahandle, m->msgnum, UID_EXACT);
int i = 0;

#if DEBUG
assert(Ahandle!=NULL);
assert(mh==NULL);
#endif

if (!Ahandle)
{
return FALSE;
}

if (mh != NULL) /* close old msg, if left open */
{
MsgCloseMsg(mh);
}

/* if (n < 0)
return ERR_OPEN_MSG; */

if (m->new) { /* if new, store current number of msgs */
/* (for use in squish_writetext()), and */
/* create a new frame for the new msg */
num_msgs = MsgGetNumMsg(Ahandle);
if ((mh = MsgOpenMsg(Ahandle, MOPEN_CREATE, 0L))==NULL)
{
return ERR_OPEN_MSG;
}
new = TRUE;
}
else
{ /* else we open the msg to be changed */
if ((mh=MsgOpenMsg(Ahandle, MOPEN_RW, n))==NULL)
{
return ERR_OPEN_MSG;
}
new = FALSE;
}

memset(&xmsg, 0, sizeof xmsg);

xmsg.attr = 0;
if (m->attrib.private) xmsg.attr |= MSGPRIVATE;
if (m->attrib.crash) xmsg.attr |= MSGCRASH;
if (m->attrib.recvd) xmsg.attr |= MSGREAD;
if (m->attrib.sent) xmsg.attr |= MSGSENT;
if (m->attrib.attached) xmsg.attr |= MSGFILE;
if (m->attrib.forward) xmsg.attr |= MSGFWD;
if (m->attrib.orphan) xmsg.attr |= MSGORPHAN;
if (m->attrib.killsent) xmsg.attr |= MSGKILL;
if (m->attrib.local) xmsg.attr |= MSGLOCAL;
if (m->attrib.hold) xmsg.attr |= MSGHOLD;
if (m->attrib.direct) xmsg.attr |= MSGXX2;
if (m->attrib.freq) xmsg.attr |= MSGFRQ;
if (m->attrib.rreq) xmsg.attr |= MSGRRQ;
if (m->attrib.rcpt) xmsg.attr |= MSGCPT;
if (m->attrib.areq) xmsg.attr |= MSGARQ;
if (m->attrib.ureq) xmsg.attr |= MSGURQ;

if (new == FALSE) { /* if the old msg had been scanned, */
/* then we make sure that the MSGSCANNED */
/* bit is set on the way out. new msgs */
/* get this bit stripped. */
if (m->scanned && !m->new) {
xmsg.attr |= MSGSCANNED;
}
}

if (m->replyto != 0) /* get the links for replies */
xmsg.replyto = MsgMsgnToUid(Ahandle, m->replyto);

for (i = 0; i < 9; i++)
{
if (m->replies[i] != 0)
{
xmsg.replies[i] = MsgMsgnToUid(Ahandle, m->replies[i]);
}
}

i = 0;

while (m->replies[i] != 0 && i < 9) i++;

if (i == 9) i = 8;

if (!m->new && replyto != 0)
{
xmsg.replies[i] = replyto;
replyto = 0;
}

xmsg.dest.zone = (word)m->to.zone;
xmsg.dest.net = (word)m->to.net;
xmsg.dest.node = (word)m->to.node;
xmsg.dest.point = (word)m->to.point;

xmsg.orig.zone = (word)m->from.zone;
xmsg.orig.net = (word)m->from.net;
xmsg.orig.node = (word)m->from.node;
xmsg.orig.point = (word)m->from.point;

if (m->isto)
memcpy(xmsg.to, m->isto, min(sizeof xmsg.to, strlen(m->isto)));

if (m->isfrom)
memcpy(xmsg.from, m->isfrom, min(sizeof xmsg.from, strlen(m->isfrom)));

if (m->subj)
memcpy(xmsg.subj, m->subj, min(sizeof xmsg.subj, strlen(m->subj)));

memcpy(xmsg.__ftsc_date, mtime(m->timestamp), 20);

xmsg.date_written = *timeTToStamp(m->timestamp);

if (m->time_arvd != 0)
{
xmsg.date_arrived = *timeTToStamp(m->time_arvd);
}
else
xmsg.date_arrived = xmsg.date_written;

if (type == WR_HEADER || !new)
{
MsgWriteMsg(mh, FALSE, &xmsg, NULL, 0L, 0L, 0L, NULL);
MsgCloseMsg(mh);
mh = NULL;
}
return TRUE;
}



/*-------------------------------------------------------------------*/
/* */
/* strip_whitel(void) */
/* */
/* strips the white spaces from the control info, copying it to */
/* the msgbuf array while it's at it. returns new length. */
/* */
/*-------------------------------------------------------------------*/

dword strip_whitel(void)
{
char *s, *c, *cptr;

cptr = cinfbuf; /* we put it in the cinfbuf, killing */
s = msgbuf; /* any \r & \n's in the process */
c = s + (strlen(s)) + 1;
while (s != c) { /* copy buffer across, ignoring any */
switch (*s) { /* fluff in the src buffer */
case '\r' :
case '\n' : s++; break;
default : *cptr++ = *s++;
}
}
*cptr = '\0';
return cptr - cinfbuf;
}


/*-------------------------------------------------------------------*/
/* */
/* squish_writetext(char *text, int n); */
/* */
/* writes msg text (and header if new msg), to the msgbase. if */
/* msg is not new and new text is larger, then it creates a new */
/* frame, while keeping the same position in the index. */
/* */
/*-------------------------------------------------------------------*/

int SquishMsgWriteText(char *text, unsigned long msgn, unsigned long mlen)
{
static char *tptr, *c;
static int ready = FALSE, ctrl = TRUE;
static unsigned long n = 0;
char cz = 0;
unsigned long clen;

if (!Ahandle)
{
return FALSE;
}

if (ready == FALSE) { /* starting on new msg; reset pntrs */
ready = TRUE;
tptr = msgbuf;
n = MsgUidToMsgn(Ahandle, msgn, UID_EXACT);
}

if (text == NULL)
{
if (ctrl) { /* no body in the msg */
if (new)
{
clen = strip_whitel();
MsgWriteMsg(mh, FALSE, &xmsg, NULL, 0L, mlen, clen,
(unsigned char *)cinfbuf);
MsgWriteMsg(mh, TRUE, NULL, (unsigned char *)&cz,
sizeof(char), mlen, 0L, NULL);
}
else
{
if ((mh=MsgOpenMsg(Ahandle, MOPEN_RW, n))==NULL)
{
ready = FALSE;
ctrl = TRUE;
new = FALSE; /* we only change the header */
return FALSE;
}
MsgWriteMsg(mh, FALSE, &xmsg, NULL, 0L, mlen, 0L, NULL);
}
}
else
MsgWriteMsg(mh, TRUE, NULL, (unsigned char *)&cz,
sizeof(char), mlen, 0L, NULL);

if (new) { /* msg is a reply - save new number so */
/* next header written can use it for */
/* the uplink number */
if (xmsg.replyto) {
replyto = MsgMsgnToUid(Ahandle, MsgGetNumMsg(Ahandle));
}
if (num_msgs == MsgGetNumMsg(Ahandle)) {
CurArea.messages--;
}
}

new = ready = FALSE;
ctrl = TRUE;
return TRUE;
}
if (*text == '\01' && ctrl)
{
c = text;
while (*c != '\0') { /* store the ctrl info */
*tptr++ = *c++;
}
*tptr = '\0';
}
else
{
if (*text != '\01' && ctrl)
{
ctrl = FALSE;
clen = strip_whitel();
if (!new) { /* we are modifying a non-new msg */
if ((mh=MsgOpenMsg(Ahandle, MOPEN_RW, n))==NULL) {
ready = FALSE;
ctrl = TRUE;
new = FALSE;
return FALSE;
}

if (MsgReadMsg(mh, &xmsg, 0L, 0L, NULL, 0L, NULL) == (dword)-1)
{
new = FALSE;
ready = FALSE;
ctrl = TRUE;
return FALSE;
}

MsgCloseMsg(mh); /* copy xmsg info across */

if ((mh=MsgOpenMsg(Ahandle, MOPEN_CREATE, n))==NULL)
{
ready = FALSE;
ctrl = TRUE;
new = FALSE;
return FALSE;
}
/* messy, but it works */
MsgWriteMsg(mh, FALSE, &xmsg, (unsigned char *)text,
strlen(text), mlen,
clen, (unsigned char *)cinfbuf);
}
else
MsgWriteMsg(mh, FALSE, &xmsg, (unsigned char *)text,
strlen(text), mlen, clen,
(unsigned char *)cinfbuf);
}
else
MsgWriteMsg(mh, TRUE, NULL, (unsigned char *)text,
strlen(text), mlen, 0L, NULL);
}
return TRUE;
}


/*---------------------------------------------------------*/
/* MsgClose() */
/* */
/* closes the message currently opened. */
/* */
/*---------------------------------------------------------*/

int SquishMsgClose(void)
{
word i;

#if DEBUG
assert(Ahandle!=NULL);
assert(mh!=NULL);
#endif

if (MsgCloseMsg(mh) == -1) {
i = msgapierr; /* debug purposes */
printf("\n!ERROR: message didn't close, error %ud", i);
exit(-1);
return ERR_CLOSE_MSG;
}
else {
mh = NULL;
return TRUE;
}
}

/*---------------------------------------------------------*/
/* MsgAreaClose() */
/* */
/* closes the area currently opened. */
/* */
/*---------------------------------------------------------*/

int SquishMsgAreaClose(void)
{
word i;

if (!Ahandle)
return TRUE;

if (MsgCloseArea(Ahandle) == -1)
{
i = msgapierr; /* debug purposes */
printf("\n!ERROR: area didn't close, error %ud", i);
exit(-1);
return ERR_CLOSE_AREA;
}
else
{
CurArea.status = 0;
Ahandle = NULL;
return TRUE;
}
}


/*---------------------------------------------------------*/
/* SquishUidToMsgn() */
/* */
/* Returns the msg# of a UID. */
/* */
/*---------------------------------------------------------*/

unsigned long SquishUidToMsgn(unsigned long n)
{
#if DEBUG
assert(Ahandle!=NULL);
#endif
return MsgUidToMsgn(Ahandle, n, UID_EXACT);
}


/*---------------------------------------------------------*/
/* SquishMsgnToUid() */
/* */
/* Returns the UID of a squish message. */
/* */
/*---------------------------------------------------------*/


unsigned long SquishMsgnToUid(unsigned long n)
{
#if DEBUG
assert(Ahandle!=NULL);
#endif
return MsgMsgnToUid(Ahandle, n);
}

/*-------------------------------------------------------------------*/
/* */
/* squish_setlast(AREA a); */
/* */
/* sets the last message read in the *.sql file & closes the msg */
/* area; if *.sql file doesn't exist, create it. */
/* */
/*-------------------------------------------------------------------*/

int SquishAreaSetLast(AREA *a)
{
char work[255];
long i = 1, k = 0;
int ret = TRUE;
int sql;

if (mh != NULL)
{
MsgCloseMsg(mh);
mh = NULL;
}
if (Ahandle != NULL) /* don't do this on closed area! */
{
sprintf(work,"%s.SQL",a->path);

sql = sopen(work, O_BINARY|O_RDWR, SH_DENYNO, S_IWRITE|S_IREAD);
if (sql == -1)
{
if (errno != EACCES && errno != EMFILE)
{
sql = sopen(work, O_BINARY|O_WRONLY|O_CREAT, SH_DENYNO, S_IWRITE|S_IREAD);
if (sql == -1)
ret = FALSE;
else
{
lseek(sql, 0L, SEEK_SET);

for (i = 0; SW->useroffset > (int) i; i++)
{
write(sql, &k, sizeof(k));
}
i = MsgMsgnToUid(Ahandle, CurArea.lastread);
write(sql, (char *) &i, sizeof(long));
close(sql);
}
}
else
ret = FALSE;
}
else
{
lseek(sql, SW->useroffset * sizeof(long), SEEK_SET);

if (SW->use_lastr)
i = MsgMsgnToUid(Ahandle, CurArea.lastread);
else
i = MsgMsgnToUid(Ahandle, CurArea.current);

write(sql, (char *) &i, sizeof(long));
close(sql);
}
}
return ret;
}


/*-------------------------------------------------------------------*/
/* */
/* MsgDelete() */
/* */
/* kills a message in the current area, specified by the passed */
/* index. */
/* */
/*-------------------------------------------------------------------*/

int SquishMsgDelete(unsigned long n)
{
unsigned long msgn;

#if DEBUG
assert(Ahandle!=NULL);
#endif
msgn = MsgUidToMsgn(Ahandle, n, UID_EXACT);

if (MsgKillMsg(Ahandle, msgn) == -1)
return FALSE;

return TRUE;
}

static time_t stampToTimeT(struct _stamp *st)
{
struct tm tms;
time_t tt;

tms.tm_sec = st->time.ss << 1;
tms.tm_min = st->time.mm;
tms.tm_hour = st->time.hh;
tms.tm_mday = st->date.da;
tms.tm_mon = st->date.mo - 1;
tms.tm_year = st->date.yr + 80;
tms.tm_isdst = -1;
tt = mktime(&tms);
return (tt);
}

static struct _stamp *timeTToStamp(time_t tt)
{
static struct _stamp st;
struct tm *tms;

tms = localtime(&tt);
st.time.ss = tms->tm_sec >> 1;
st.time.mm = tms->tm_min;
st.time.hh = tms->tm_hour;
st.date.da = tms->tm_mday;
st.date.mo = tms->tm_mon + 1;
st.date.yr = tms->tm_year - 80;
return (&st);
}

/*-- end --*/


  3 Responses to “Category : Recently Uploaded Files
Archive   : MSQ320.ZIP
Filename : MSG.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/