/*
* MSG.C
*
* Written on 10-Jul-94 by John Dennis and released to the public domain.
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <assert.h>
#if !defined(UNIX) && !defined(SASC)
#include <io.h>
#endif
#if defined(UNIX) || defined(__CYGWIN__)
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef __MSC__
#include <sys/locking.h>
#endif
#if !defined(UNIX) && !defined(SASC) && !defined(__CYGWIN__)
#include <share.h>
#endif
#include <smapi/msgapi.h>
#include "addr.h"
#include "nedit.h"
#include "msged.h"
#include "memextra.h"
#include "date.h"
#include "normal.h"
#include "unused.h"
#include "msg.h"
#include "charset.h"
static char *cinfbuf = NULL; /* control info buffer, size BUFLEN */
static unsigned long num_msgs; /* number of messages in msgbase */
static unsigned long new = 0; /* if msg being written is new */
static time_t stampToTimeT(struct _stamp *st);
static struct _stamp *timeTToStamp(time_t);
static struct _minf minf;
static MSG *Ahandle = NULL; /* area handle */
static MSGH *mh = NULL; /* message handle */
static XMSG xmsg; /* squish message header */
/* these are used by the JAM routines only */
static char *global_text = NULL;
static unsigned long global_pos = 0;
static unsigned long global_len;
static unsigned long global_msgn;
static int global_ctrl = 1;
static int ready = FALSE, ctrl = TRUE;
static UMSGID replyto = 0; /* to ensure correct uplinks when mxx is used */
/* Make Msged work with both stable and current smapi: */
#ifndef S_IMODE
#define S_IMODE S_IREAD | S_IWRITE
#endif
/*
* SquishMsgAreaOpen; Scans an area for messages, opening the message
* base and filling the message[] array.
*/
long SquishMsgAreaOpen(AREA * a)
{
unsigned long lastread; /* lastread record */
char work[256]; /* path to sql file */
int sql; /* file handle */
unsigned long k = 0; /* counter */
struct stat bstat; /* stats for sql file */
unsigned char buffer[4]; /* for reading and writing the sql */
a->scanned = 1;
a->last = 1;
a->first = 1;
a->lastread = 0;
a->current = 0;
a->status = 0;
/* open the msgbase */
if (mh != NULL)
{
MsgCloseMsg(mh);
mh = NULL;
}
if (Ahandle != NULL)
{
if (SW->squish_lock)
{
MsgUnlock(Ahandle);
}
if (MsgCloseArea(Ahandle) == -1)
{
return 0;
}
}
Ahandle = MsgOpenArea((byte *)a->path, MSGAREA_CRIFNEC,
((a->msgtype == JAM) ? MSGTYPE_JAM:MSGTYPE_SQUISH));
if (Ahandle == NULL)
{
return 0;
}
if (SW->squish_lock)
{
if (MsgLock(Ahandle) == -1) /* Lock failed - return */
{
MsgCloseArea(Ahandle);
Ahandle = NULL;
return 0;
}
}
sprintf(work, "%s.sql", a->path);
sql = sopen(work, O_BINARY | O_RDONLY, SH_DENYNO, S_IMODE);
if (sql != -1)
{
#if defined(PACIFIC) || defined(LATTICE)
stat(work, &bstat);
#else
fstat(sql, &bstat);
#endif
/* we make it big enough */
if (bstat.st_size < SW->useroffset * 4)
{
close(sql);
sql = sopen(work, O_BINARY | O_RDWR, SH_DENYNO, S_IMODE);
if (sql != -1)
{
#if defined(PACIFIC) || defined(LATTICE)
stat(work, &bstat);
#else
fstat(sql, &bstat);
#endif
lastread = 0;
buffer[0] = buffer[1] = buffer[2] = buffer[3] = '\0';
k = bstat.st_size / 4;
lseek(sql, 0L, SEEK_END);
while (SW->useroffset > k)
{
farwrite(sql, buffer, 4);
k++;
}
}
}
else
{
/* we read the data in */
lseek(sql, SW->useroffset * 4, SEEK_SET);
if (farread(sql, buffer, 4) == 4)
{
lastread = buffer[0] + (((unsigned long)(buffer[1])) << 8) +
(((unsigned long)(buffer[2])) << 16) +
(((unsigned long)(buffer[3])) << 24);
if (CurArea.netmail)
{
a->lastread = MsgUidToMsgn(Ahandle, lastread, UID_PREV);
}
else
{
a->lastread = MsgUidToMsgn(Ahandle, lastread, UID_NEXT);
}
a->current = a->lastread;
}
}
close(sql);
}
if (Ahandle->type != MSGTYPE_JAM)
a->last = MsgHighMsg(Ahandle);
else
a->last = Ahandle->num_msg; /* work around bug in JAM api */
a->status = 1;
if (a->last >= 1 && a->current == 0)
{
a->lastread = 0;
a->current = 1;
}
return a->last;
}
/*
* SquishMsgReadHeader; Reads in the message header and control
* information for the message.
*/
msg *SquishMsgReadHeader(unsigned long n, int type)
{
char path[PATHLEN];
msg *m;
int i = 0;
if (cinfbuf == NULL) cinfbuf = xmalloc(BUFLEN);
if (Ahandle == NULL)
{
return NULL;
}
if (mh != NULL)
{
/* if open, close it */
MsgCloseMsg(mh);
}
/* open msg we want to open */
mh = MsgOpenMsg(Ahandle, MOPEN_READ, n);
if (mh == NULL)
{
return NULL;
}
if (MsgReadMsg(mh, &xmsg, 0L, 0L, NULL, BUFLEN, (byte *) cinfbuf) == (dword) - 1)
{
/* no message header or control info! */
MsgCloseMsg(mh);
mh = NULL;
return NULL;
}
m = xcalloc(1, sizeof *m);
/* 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);
}
m->isto = xcalloc(1, sizeof xmsg.to + 1);
m->isfrom = xcalloc(1, sizeof xmsg.from + 1);
m->subj = xcalloc(1, sizeof xmsg.subj + 1);
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.priv = (xmsg.attr & MSGPRIVATE) != 0;
m->attrib.crash = (xmsg.attr & MSGCRASH) != 0;
m->attrib.rcvd = (xmsg.attr & MSGREAD) != 0;
m->attrib.sent = (xmsg.attr & MSGSENT) != 0;
m->attrib.attach = (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;
m->attrib.lock = (xmsg.attr & MSGLOCKED) != 0;
if (xmsg.attr & MSGSCANNED)
{
m->scanned = 1;
}
if (type != RD_HEADER_BRIEF)
{
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 = 1;
m->from.fidonet = 1;
if (type == RD_HEADER || type == RD_HEADER_BRIEF)
{
MsgCloseMsg(mh);
mh = NULL;
}
return m;
}
/*
* SquishMsgReadText; Reads in the entire message, adds the control
* information 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 correspoding Fido function.
*/
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;
unused(n);
if (Ahandle == NULL)
{
return NULL;
}
if (cinfbuf == NULL) cinfbuf = xmalloc(BUFLEN);
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)>=BUFLEN) ? (BUFLEN - 1) :
MsgGetCtrlLen(mh))) = '\0';
if (*t != '\0')
{
*next++ = *t++;
while (*t != '\0' && next - msgbuf < BUFLEN - 2)
{
if (*t == '\01')
{
*next++ = '\r'; /* add a \r to the text */
}
if (next - msgbuf < BUFLEN - 2)
{
*next++ = *t++;
}
}
if (*(next - 1) == '\01')
{
next--;
*(next) = '\0';
}
else
{
if (next - msgbuf < BUFLEN - 2)
{
*next++ = '\r';
}
*next = '\0'; /* terminate string */
}
}
next = msgbuf;
end = 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, (byte *) 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,
(byte *)(msgbuf + (size_t) l), 0L, NULL);
ofs += i;
if (i < 1)
{
next = NULL;
return xstrdup(msgbuf);
}
*(msgbuf + (size_t) l + (size_t) i) = '\0';
end = msgbuf + l + normalize(msgbuf + (size_t) l);
next = msgbuf;
t = strchr(next, '\n');
}
if (t != NULL)
{
eol = *(t + 1);
*(t + 1) = '\0';
}
text = xstrdup(next);
if (t != NULL)
{
*(t + 1) = eol;
next = t + 1;
}
else
{
next = NULL;
}
return text;
}
/*
* SquishMsgWriteHeader; Writes message header to the message base,
* creates new frame if new message, and makes sure links are correct.
*/
int SquishMsgWriteHeader(msg * m, int type)
{
unsigned long n;
int i = 0;
n = MsgUidToMsgn(Ahandle, m->msgnum, UID_EXACT);
if (Ahandle == NULL)
{
return FALSE;
}
if (mh != NULL) /* close old msg, if left open */
{
MsgCloseMsg(mh);
}
if (m->new)
{
/*
* If new, store current number of messages (for use in
* SquishMsgWriteText, and create a new frame for the new
* message.
*/
num_msgs = MsgGetNumMsg(Ahandle);
mh = MsgOpenMsg(Ahandle, MOPEN_CREATE, 0L);
if (mh == NULL)
{
return ERR_OPEN_MSG;
}
new = TRUE;
}
else
{
/* else we open the message to be changed */
mh = MsgOpenMsg(Ahandle, MOPEN_RW, n);
if (mh == NULL)
{
return ERR_OPEN_MSG;
}
new = FALSE;
}
memset(&xmsg, 0, sizeof xmsg);
xmsg.attr = 0;
if (m->attrib.priv)
{
xmsg.attr |= MSGPRIVATE;
}
if (m->attrib.crash)
{
xmsg.attr |= MSGCRASH;
}
if (m->attrib.rcvd)
{
xmsg.attr |= MSGREAD;
}
if (m->attrib.sent)
{
xmsg.attr |= MSGSENT;
}
if (m->attrib.attach)
{
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 (m->attrib.lock)
{
xmsg.attr |= MSGLOCKED;
}
if (new == FALSE)
{
/*
* If the old message had been scanned, then we make sure that
* the MSGSCANNED bit is set on the way out. New messages 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 != NULL)
{
memcpy(xmsg.to, m->isto, min(sizeof xmsg.to, strlen(m->isto)));
}
if (m->isfrom != NULL)
{
memcpy(xmsg.from, m->isfrom, min(sizeof xmsg.from, strlen(m->isfrom)));
}
if (m->subj != NULL)
{
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; Strips the white spaces from the control info,
* copying it to the msgbuf array while it's at it. Returns new
* length.
*/
static dword strip_whitel(void)
{
char *s, *c, *cptr;
if (cinfbuf == NULL) cinfbuf = xmalloc(BUFLEN);
/* we put it in the cinfbuf, killing any \r & \n's in the process */
cptr = cinfbuf;
s = msgbuf;
c = s + strlen(s) + 1;
while (s != c)
{
/* copy buffer across, ignoring any fluff in the source buffer */
switch (*s)
{
case '\r':
case '\n':
s++;
break;
default:
*cptr++ = *s++;
break;
}
}
*cptr = '\0';
return cptr - cinfbuf;
}
int JamMsgWriteText(char *text, unsigned long msgn, unsigned long mlen)
{
int l;
if (global_ctrl)
{
if (text != NULL && *text != '\01')
{
global_ctrl = 0;
}
else
{
return SquishMsgWriteText(text, msgn, mlen);
}
}
if (global_text == NULL)
{
global_text = xmalloc(mlen + 1);
global_pos = 0;
global_len = mlen;
global_msgn = msgn;
}
if (text != NULL)
l = strlen(text);
else
l = 0;
assert(global_len == mlen);
assert(global_pos + l <= mlen);
if (l)
{
memcpy(global_text + global_pos, text, l);
global_text[global_pos + l] = '\0';
global_pos += l;
}
return TRUE;
}
/*
* SquishMsgWriteText; Writes message text (and header if a new
* message), to the message base. If the message is not new and
* new text is larger, 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 unsigned long n = 0;
char cz = 0;
unsigned long clen;
if (Ahandle == NULL)
{
return FALSE;
}
if (cinfbuf == NULL) cinfbuf = xmalloc(BUFLEN);
if (ready == FALSE)
{
/* starting on new message; reset pointers */
ready = TRUE;
tptr = msgbuf;
n = MsgUidToMsgn(Ahandle, msgn, UID_EXACT);
}
if (text == NULL)
{
if (ctrl)
{
/* no body in the message */
if (new)
{
clen = strip_whitel();
/* we could fix this to not use append. */
MsgWriteMsg(mh, FALSE, &xmsg, NULL, 0L, mlen, clen,
(byte *)cinfbuf);
MsgWriteMsg(mh, TRUE, NULL, (byte *)&cz,
sizeof(char), mlen, 0L, NULL);
}
else
{
mh = MsgOpenMsg(Ahandle, MOPEN_RW, n);
if (mh == NULL)
{
ready = FALSE;
ctrl = TRUE;
new = FALSE; /* we only change the header */
return FALSE;
}
MsgWriteMsg(mh, FALSE, &xmsg, NULL, 0L, mlen, 0L, NULL);
}
}
else
{
/* I THINK we might also be able to fix this
not to use append. */
MsgWriteMsg(mh, TRUE, NULL, (byte *)&cz, sizeof(char),
mlen, 0L, NULL);
}
if (new)
{
/*
* Message 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 control info */
*tptr++ = *c++;
}
*tptr = '\0';
}
else
{
if (*text != '\01' && ctrl)
{
ctrl = FALSE;
clen = strip_whitel();
if (!new)
{
/* we are modifying a non-new message */
mh = MsgOpenMsg(Ahandle, MOPEN_RW, n);
if (mh == 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 information across */
mh = MsgOpenMsg(Ahandle, MOPEN_CREATE, n);
if (mh == NULL)
{
ready = FALSE;
ctrl = TRUE;
new = FALSE;
return FALSE;
}
/* messy, but it works */
MsgWriteMsg(mh, FALSE, &xmsg, (byte *)text,
strlen(text), mlen, clen, (byte *)cinfbuf);
}
else
{
/* we'd need to intercept this call if we want
to make it work with JAM api */
MsgWriteMsg(mh, FALSE, &xmsg, (byte *)text,
strlen(text), mlen, clen, (byte *)cinfbuf);
}
}
else
{
/* this does NOT work with JAM api */
MsgWriteMsg(mh, TRUE, NULL, (byte *)text, strlen(text),
mlen, 0L, NULL);
}
}
return TRUE;
}
int JamMsgClose(void)
{
int rv = TRUE;
int srv = TRUE;
if (global_text != NULL)
{
if (SquishMsgWriteText(global_text, global_msgn, global_len) != TRUE)
rv = ERR_CLOSE_MSG;
xfree(global_text);
global_ctrl = 1; /* reset! */
global_text = NULL;
global_pos = 0;
}
srv = SquishMsgClose();
return (rv != TRUE ? rv : srv);
}
/*
* SquishMsgClose; Closes the message currently opened.
*/
int SquishMsgClose(void)
{
if (mh == NULL)
{
return TRUE;
}
if (MsgCloseMsg(mh) == -1)
{
printf("\n!SquishMsgClose(): Message didn't close, error %ud!\n", msgapierr);
exit(-1);
return ERR_CLOSE_MSG;
}
else
{
ready = FALSE; ctrl = TRUE;
mh = NULL;
return TRUE;
}
}
/*
* Area locking functions
*/
int SquishMsgLock(void)
{
if (!SW->squish_lock)
{
return MsgLock(Ahandle);
}
else
{
return 0; /* area already locked */
}
}
int SquishMsgUnlock(void)
{
if (!SW->squish_lock)
{
return MsgUnlock(Ahandle);
}
else
{
return 0;
}
}
/*
* SquishMsgAreaClose; Closes the area currently opened.
*/
int SquishMsgAreaClose(void)
{
if (Ahandle == NULL)
{
return TRUE;
}
if (SW->squish_lock)
{
MsgUnlock(Ahandle);
}
if (MsgCloseArea(Ahandle) == -1)
{
printf("\n!SquishMsgAreaClose(): Area didn't close, error %ud!\n", msgapierr);
exit(-1);
return ERR_CLOSE_AREA;
}
else
{
CurArea.status = 0;
Ahandle = NULL;
return TRUE;
}
}
/*
* SquishUidToMsgn; Returns the corresponding message number of a UID.
*/
unsigned long SquishUidToMsgn(unsigned long n)
{
return MsgUidToMsgn(Ahandle, n, UID_EXACT);
}
/*
* SquishMsgnToUid; Returns the corresponding UID of a message number.
*/
unsigned long SquishMsgnToUid(unsigned long n)
{
return MsgMsgnToUid(Ahandle, n);
}
/*
* SquishAreaSetLast; Sets the last message read in the .sql file and
* closes the message area. If the .sql file doesn't exist, create it.
*/
int SquishAreaSetLast(AREA * a)
{
char work[255];
long i = 1;
int ret = TRUE;
int fd;
unsigned char buffer[4];
if (mh != NULL)
{
MsgCloseMsg(mh);
mh = NULL;
}
if (Ahandle != NULL)
{
sprintf(work, "%s.sql", a->path);
fd = sopen(work, O_BINARY | O_RDWR, SH_DENYNO, S_IMODE);
if (fd == -1)
{
if (errno != EACCES && errno != EMFILE)
{
fd = sopen(work, O_BINARY | O_WRONLY | O_CREAT, SH_DENYNO,
S_IMODE);
if (fd == -1)
{
ret = FALSE;
}
else
{
buffer[0] = buffer[1] = buffer[2] = buffer[3] = '\0';
lseek(fd, 0L, SEEK_SET);
for (i = 0; SW->useroffset > (int)i; i++)
{
farwrite(fd, buffer, 4);
}
i = MsgMsgnToUid(Ahandle, CurArea.lastread);
buffer[0] = i & 0xFF;
buffer[1] = (i >> 8) & 0xFF;
buffer[2] = (i >> 16) & 0xFF;
buffer[3] = (i >> 24) & 0xFF;
farwrite(fd, buffer, 4);
close(fd);
}
}
else
{
ret = FALSE;
}
}
else
{
lseek(fd, SW->useroffset * 4, SEEK_SET);
if (SW->use_lastr)
{
i = MsgMsgnToUid(Ahandle, CurArea.lastread);
}
else
{
i = MsgMsgnToUid(Ahandle, CurArea.current);
}
buffer[0] = i & 0xFF;
buffer[1] = (i >> 8) & 0xFF;
buffer[2] = (i >> 16) & 0xFF;
buffer[3] = (i >> 24) & 0xFF;
farwrite(fd, buffer, 4);
close(fd);
}
}
return ret;
}
/*
* SquishMsgDelete; Erases a message in the current area, specified
* by the passed index.
*/
int SquishMsgDelete(unsigned long n)
{
unsigned long msgn;
msgn = MsgUidToMsgn(Ahandle, n, UID_EXACT);
if (MsgKillMsg(Ahandle, msgn) == -1)
{
return FALSE;
}
return TRUE;
}
static time_t stampToTimeT(struct _stamp *st)
{
time_t tt;
struct tm tms;
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)
{
struct tm *tmsp;
static struct _stamp st;
tmsp = localtime(&tt);
st.time.ss = tmsp->tm_sec >> 1;
st.time.mm = tmsp->tm_min;
st.time.hh = tmsp->tm_hour;
st.date.da = tmsp->tm_mday;
st.date.mo = tmsp->tm_mon + 1;
st.date.yr = tmsp->tm_year - 80;
return &st;
}
void MsgApiInit(void)
{
minf.def_zone = 0; /* set default zone */
minf.req_version = 0; /* level 0 of the MsgAPI */
MsgOpenApi(&minf); /* init the MsgAPI */
}
void MsgApiTerm(void)
{
MsgCloseApi();
}
syntax highlighted by Code2HTML, v. 0.9.1