/*
* ratStdFolder.c --
*
* This file contains code which implements standard c-client folders.
* This means ONLY filefolders at this moment.
*
* TkRat software and its included text is Copyright 1996-2002 by
* Martin Forssén
*
* The full text of the legal notice is contained in the file called
* COPYRIGHT, included with this distribution.
*/
#include "ratStdFolder.h"
/*
* We use this structure to keep a list of open connections
*/
typedef struct Connection {
MAILSTREAM *stream; /* Handler to c-client entity */
int *errorFlagPtr; /* Address of flag to set on hard errors */
int refcount; /* references count */
int closing; /* True if this connection is unused and
waiting to be closed */
int isnet; /* Nonnull if this is a network conn */
Tcl_TimerToken token; /* Timer token for closing timer */
struct Connection *next; /* Struct linkage */
FolderHandlers *handlers; /* Event handlers */
} Connection;
FolderHandlers **globHD;
/*
* Remember if we must initialize the package
*/
static int initialize = 1;
/*
* List of open connections
*/
static Connection *connListPtr = NULL;
/*
* The values below are used to catch calls to mm_log. That is when you
* want to handle the message internally.
*/
static RatLogLevel logLevel;
static char *logMessage = NULL;
int logIgnore = 0;
/*
* These variables are used by mm_login
*/
static char loginPassword[MAILTMPLEN];
static char loginSpec[MAILTMPLEN];
static int loginStore;
/*
* This is used to build a list of found mailboxes when listing
*/
typedef struct Mailbox {
char *name; /* The en component of name the mailbox name */
char *folder; /* The mailbox name */
long attributes; /* The attributes from c-client */
int delimiter; /* The delimiter in the folder names */
struct Mailbox *next; /* Pointer to the next mailbox on this level */
struct Mailbox *child; /* Pointer to subfolders */
} Mailbox;
static Mailbox *mailboxListPtr = NULL;
static char *mailboxSearchBase = NULL;
static char lastDelimiter[2] = {'\0', '\0'};
/*
* Used to store search results
*/
long *searchResultPtr = NULL;
int searchResultSize = 0;
int searchResultNum = 0;
/*
* Used to store status results
*/
MAILSTATUS stdStatus;
/*
* File handler of debugging file
*/
static FILE *debugFile = NULL;
/*
* Procedures private to this module.
*/
static RatInitProc Std_InitProc;
static RatCloseProc Std_CloseProc;
static RatUpdateProc Std_UpdateProc;
static RatInsertProc Std_InsertProc;
static RatSetFlagProc Std_SetFlagProc;
static RatGetFlagProc Std_GetFlagProc;
static Tcl_TimerProc CloseConnection;
static Tcl_ObjCmdProc StdImportCmd;
static Connection *FindConn(MAILSTREAM *stream);
static void StdImportBuildResult(Tcl_Interp *interp, Mailbox *mPtr,
int *lastId, int id,
int templatec, Tcl_Obj **templatev);
static HandleExists Std_HandleExists;
static HandleExpunged Std_HandleExpunged;
static RatStdFolderType Std_GetType(const char *spec);
/*
*----------------------------------------------------------------------
*
* RatStdFolderInit --
*
* Initializes the file folder command.
*
* Results:
* The return value is normally TCL_OK; if something goes wrong
* TCL_ERROR is returned and an error message will be left in
* the result area.
*
* Side effects:
* The C-client library is initialized and the apropriate mail drivers
* are linked.
*
*
*----------------------------------------------------------------------
*/
int
RatStdFolderInit(Tcl_Interp *interp)
{
/* Link imap code */
#include "../imap/c-client/linkage.c"
Tcl_CreateObjCommand(interp, "RatImport", StdImportCmd, NULL, NULL);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Std_StreamOpen --
*
* Opens a standard c-client mailstream. This function handles
* caching of passwords and connections.
*
* Results:
* The mail stream.
*
* Side effects:
* The caches may be modified.
*
*----------------------------------------------------------------------
*/
MAILSTREAM*
Std_StreamOpen(Tcl_Interp *interp, char *spec, long options,
int *errorFlagPtr, FolderHandlers *handlers)
{
MAILSTREAM *stream = NULL;
Connection *connPtr = NULL;
char *host = NULL, *cPtr;
int len;
if ('{' == spec[0]) {
strlcpy(loginSpec, spec, sizeof(loginSpec));
cPtr = strchr(loginSpec, '}');
cPtr[1] = '\0';
len = strchr(spec, '}') - spec;
if (NULL != (cPtr = strstr(spec, "/debug}"))) {
len = cPtr-spec;
}
for (connPtr = connListPtr; connPtr; connPtr = connPtr->next) {
if ((connPtr->closing || options & OP_HALFOPEN)
&& !strncmp(spec, connPtr->stream->mailbox, len)) {
break;
}
}
if (connPtr) {
stream = connPtr->stream;
connPtr->refcount++;
Tcl_DeleteTimerHandler(connPtr->token);
if (connPtr->closing) {
connPtr->handlers = handlers;
connPtr->errorFlagPtr = errorFlagPtr;
}
connPtr->closing = 0;
}
}
if (stream && options & OP_HALFOPEN) {
ckfree(host);
return stream;
}
loginPassword[0] = '\0';
stream = mail_open(stream, spec, options);
if (stream && !connPtr) {
connPtr = (Connection*)ckalloc(sizeof(Connection));
connPtr->stream = stream;
connPtr->errorFlagPtr = errorFlagPtr;
connPtr->refcount = 1;
connPtr->closing = 0;
connPtr->handlers = handlers;
connPtr->next = connListPtr;
connPtr->token = NULL;
connPtr->isnet = (('{' == spec[0]) ? 1 : 0);
connListPtr = connPtr;
if (loginPassword[0] != '\0') {
RatCachePassword(interp, spec, loginPassword, loginStore);
memset(loginPassword, 0, strlen(loginPassword));
}
}
if (!stream && '{' == spec[0]) {
Tcl_Obj *oPtr;
int n;
oPtr = Tcl_GetVar2Ex(interp, "ratNetOpenFailures",
NULL, TCL_GLOBAL_ONLY);
Tcl_GetIntFromObj(interp, oPtr, &n);
Tcl_SetVar2Ex(interp, "ratNetOpenFailures", NULL, Tcl_NewIntObj(++n),
TCL_GLOBAL_ONLY);
}
if (errorFlagPtr) {
*errorFlagPtr = 0;
}
ckfree(host);
return stream;
}
/*
*----------------------------------------------------------------------
*
* Std_StreamClose --
*
* Closes a standard c-client mailstream. This function handles
* caching of passwords and connections.
*
* Results:
* None.
*
* Side effects:
* The caches may be modified.
*
*----------------------------------------------------------------------
*/
void
Std_StreamClose(Tcl_Interp *interp, MAILSTREAM *stream)
{
Connection *connPtr;
Tcl_Obj *oPtr;
for (connPtr = connListPtr;
connPtr && stream != connPtr->stream;
connPtr = connPtr->next);
if (connPtr) {
int timeout, doCache;
if (--connPtr->refcount) {
return;
}
oPtr = Tcl_GetVar2Ex(interp, "option", "cache_conn",
TCL_GLOBAL_ONLY);
Tcl_GetBooleanFromObj(interp, oPtr, &doCache);
if (doCache && RAT_IMAP == Std_GetType(connPtr->stream->mailbox)
&& (!connPtr->errorFlagPtr || 0 == *connPtr->errorFlagPtr)) {
oPtr = Tcl_GetVar2Ex(interp, "option", "cache_conn_timeout",
TCL_GLOBAL_ONLY);
Tcl_GetIntFromObj(interp, oPtr, &timeout);
connPtr->closing = 1;
if (connPtr->errorFlagPtr) {
connPtr->errorFlagPtr = NULL;
}
if (timeout) {
connPtr->token = Tcl_CreateTimerHandler(timeout*1000,
CloseConnection, (ClientData)connPtr);
} else {
connPtr->token = NULL;
}
} else {
CloseConnection((ClientData)connPtr);
}
} else {
logIgnore++;
mail_close_full(stream, NIL);
logIgnore--;
}
}
/*
*----------------------------------------------------------------------
*
* Std_StreamCloseAllCached --
*
* Forces a close of all cached connections
*
* Results:
* None.
*
* Side effects:
* The caches may be modified.
*
*----------------------------------------------------------------------
*/
void
Std_StreamCloseAllCached(Tcl_Interp *interp)
{
Connection *connPtr, *nextPtr;
for (connPtr = connListPtr; connPtr; connPtr = nextPtr) {
nextPtr = connPtr->next;
if (connPtr->closing) {
Tcl_DeleteTimerHandler(connPtr->token);
CloseConnection((ClientData)connPtr);
}
}
}
/*
*----------------------------------------------------------------------
*
* OpenStdFolder --
*
* Opens a standard c-client folder and if it is a filefolder and
* is of an incompatible format (unfortunately generated by an older
* version of this program) we convert it.
*
* Results:
* The mail stream.
*
* Side effects:
* None.
*
*
*----------------------------------------------------------------------
*/
MAILSTREAM*
OpenStdFolder(Tcl_Interp *interp, char *spec, void *voidPtr)
{
MAILSTREAM *stream = NULL;
RatStdFolderType type;
StdFolderInfo *stdPtr = (StdFolderInfo*)voidPtr;
Tcl_DString dsBuf;
struct stat sbuf;
int dsBufUse = 0;
type = Std_GetType(spec);
if (RAT_UNIX == type) {
spec = Tcl_UtfToExternalDString(NULL, spec, -1, &dsBuf);
dsBufUse = 1;
}
if ('/' == spec[0] && stat(spec, &sbuf) && ENOENT == errno) {
int fd;
fd = open(spec, O_CREAT | O_WRONLY, 0600);
close(fd);
}
logLevel = RAT_BABBLE;
stream = Std_StreamOpen(interp, spec, 0, (stdPtr ? &stdPtr->error : NULL),
(stdPtr ? &stdPtr->handlers : NULL));
if (logLevel > RAT_WARN) {
Tcl_SetResult(interp, logMessage, TCL_VOLATILE);
return NULL;
}
if (NIL == stream) {
Tcl_AppendResult(interp, "Failed to open std mailbox \"",
spec, "\"", (char *) NULL);
return NULL;
}
if (!strcmp(stream->dtb->name, "mbx")) {
type = RAT_MBX;
}
if (stdPtr) {
stdPtr->stream = stream;
stdPtr->referenceCount = 1;
stdPtr->exists = stream->nmsgs;
stdPtr->type = type;
}
if (dsBufUse) {
Tcl_DStringFree(&dsBuf);
}
return stream;
}
/*
*----------------------------------------------------------------------
*
* RatStdFolderCreate --
*
* Creates a std folder entity.
*
* Results:
* The return value is normally TCL_OK; if something goes wrong
* TCL_ERROR is returned and an error message will be left in
* the result area.
*
* Side effects:
* A std folder is created.
*
*
*----------------------------------------------------------------------
*/
RatFolderInfo*
RatStdFolderCreate(Tcl_Interp *interp, Tcl_Obj *defPtr)
{
RatFolderInfo *infoPtr;
StdFolderInfo *stdPtr;
MAILSTREAM *stream = NULL;
char buf[32];
Tcl_Obj *oPtr;
char *spec;
int i;
/*
* Now it is time to initialize things
*/
if (initialize) {
char *role, *domain;
role = Tcl_GetVar2(interp, "option", "default_role",TCL_GLOBAL_ONLY);
domain = RatGetCurrent(interp, RAT_HOST, role);
env_parameters(SET_LOCALHOST, (void*)domain);
initialize = 0;
}
stdPtr = (StdFolderInfo *) ckalloc(sizeof(*stdPtr));
stdPtr->handlers.state = (void*)stdPtr;
stdPtr->handlers.exists = Std_HandleExists;
stdPtr->handlers.expunged = Std_HandleExpunged;
if (NULL == (spec = RatGetFolderSpec(interp, defPtr))
|| NULL == (stream = OpenStdFolder(interp, spec, stdPtr))) {
ckfree(stdPtr);
return NULL;
}
infoPtr = (RatFolderInfo *) ckalloc(sizeof(*infoPtr));
infoPtr->type = "std";
Tcl_ListObjIndex(interp, defPtr, 0, &oPtr);
infoPtr->name = cpystr(Tcl_GetString(oPtr));
infoPtr->size = -1;
infoPtr->number = stream->nmsgs;
infoPtr->recent = stream->recent;
infoPtr->unseen = 0;
if (stream->nmsgs) {
sprintf(buf, "1:%ld", stream->nmsgs);
mail_fetchfast_full(stream, buf, NIL);
for (i = 1; i <= stream->nmsgs; i++)
if (!mail_elt (stream,i)->seen) infoPtr->unseen++;
}
infoPtr->initProc = Std_InitProc;
infoPtr->finalProc = NULL;
infoPtr->closeProc = Std_CloseProc;
infoPtr->updateProc = Std_UpdateProc;
infoPtr->insertProc = Std_InsertProc;
infoPtr->setFlagProc = Std_SetFlagProc;
infoPtr->getFlagProc = Std_GetFlagProc;
infoPtr->infoProc = Std_InfoProc;
infoPtr->setInfoProc = Std_SetInfoProc;
infoPtr->createProc = Std_CreateProc;
infoPtr->syncProc = NULL;
infoPtr->private = (ClientData) stdPtr;
return infoPtr;
}
/*
*----------------------------------------------------------------------
*
* Std_InitProc --
*
* See the documentation for initProc in ratFolder.h
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the documentation for initProc in ratFolder.h
*
*
*----------------------------------------------------------------------
*/
static void
Std_InitProc(RatFolderInfoPtr infoPtr, Tcl_Interp *interp, int index)
{
StdFolderInfo *stdPtr = (StdFolderInfo *) infoPtr->private;
MessageInfo *msgPtr;
int i, j, start, end;
if (-1 == index) {
start = 0;
end = infoPtr->number;
} else {
start = index;
end = start+1;
}
for (i=start; i<end; i++) {
msgPtr = (MessageInfo*)ckalloc(sizeof(MessageInfo));
msgPtr->folderInfoPtr = infoPtr;
msgPtr->name[0] = '\0';
msgPtr->type = RAT_CCLIENT_MESSAGE;
msgPtr->bodyInfoPtr = NULL;
msgPtr->msgNo = i;
msgPtr->fromMe = RAT_ISME_UNKOWN;
msgPtr->toMe = RAT_ISME_UNKOWN;
msgPtr->clientData = NULL;
for (j=0; j<RAT_FOLDER_END; j++) {
msgPtr->info[j] = NULL;
}
infoPtr->privatePtr[i] = (ClientData)msgPtr;
}
RatStdMsgStructInit(infoPtr, interp, index, stdPtr->stream, stdPtr->type);
}
/*
*----------------------------------------------------------------------
*
* CloseStdFolder --
*
* See the documentation for closeProc in ratFolder.h
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the documentation for closeProc in ratFolder.h
*
*
*----------------------------------------------------------------------
*/
void
CloseStdFolder(Tcl_Interp *interp, MAILSTREAM *stream)
{
Std_StreamClose(interp, stream);
}
/*
*----------------------------------------------------------------------
*
* Std_CloseProc --
*
* See the documentation for closeProc in ratFolder.h
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the documentation for closeProc in ratFolder.h
*
*
*----------------------------------------------------------------------
*/
static int
Std_CloseProc(RatFolderInfoPtr infoPtr, Tcl_Interp *interp, int expunge)
{
StdFolderInfo *stdPtr = (StdFolderInfo *) infoPtr->private;
MessageInfo *msgPtr;
int i, j;
if (stdPtr->stream) {
if (expunge) {
logIgnore++;
mail_expunge(stdPtr->stream);
logIgnore--;
}
Std_StreamClose(interp, stdPtr->stream);
}
if (0 == --stdPtr->referenceCount) {
for (i=0; i<infoPtr->number; i++) {
if (NULL == infoPtr->msgCmdPtr[i]) {
msgPtr = (MessageInfo*)infoPtr->privatePtr[i];
if (msgPtr) {
for (j=0; j<RAT_FOLDER_END; j++) {
if (msgPtr->info[j]) {
Tcl_DecrRefCount(msgPtr->info[j]);
msgPtr->info[j] = NULL;
}
}
ckfree(msgPtr->clientData);
ckfree(infoPtr->privatePtr[i]);
}
}
}
ckfree(stdPtr);
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Std_UpdateProc --
*
* See the documentation for updateProc in ratFolder.h
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the documentation for updateProc in ratFolder.h
*
*
*----------------------------------------------------------------------
*/
static int
Std_UpdateProc(RatFolderInfoPtr infoPtr, Tcl_Interp *interp,RatUpdateType mode)
{
StdFolderInfo *stdPtr = (StdFolderInfo *) infoPtr->private;
int numNew = 0, oldExists, i;
char sequence[16];
if (RAT_SYNC == mode) {
MESSAGECACHE *cachePtr;
MessageInfo *msgPtr;
int i, offset = 0;
if (infoPtr->number) {
for (i=0; i<infoPtr->number; i++) {
cachePtr = mail_elt(stdPtr->stream, i+1);
if (cachePtr->deleted) {
if (-1 != infoPtr->size) {
infoPtr->size -= cachePtr->rfc822_size;
}
if (infoPtr->msgCmdPtr[i]) {
RatMessageDelete(interp, infoPtr->msgCmdPtr[i]);
}
offset++;
} else if (offset) {
infoPtr->msgCmdPtr[i-offset] = infoPtr->msgCmdPtr[i];
infoPtr->privatePtr[i-offset] = infoPtr->privatePtr[i];
if (infoPtr->privatePtr[i]) {
msgPtr = (MessageInfo*)infoPtr->privatePtr[i];
msgPtr->msgNo = i - offset;
}
}
}
for (i=infoPtr->number-offset; i<infoPtr->number; i++) {
infoPtr->msgCmdPtr[i] = NULL;
infoPtr->privatePtr[i] = NULL;
}
}
mail_expunge(stdPtr->stream);
numNew = stdPtr->exists - (infoPtr->number - offset);
} else if (RAT_CHECKPOINT == mode) {
oldExists = infoPtr->number;
mail_check(stdPtr->stream);
numNew = stdPtr->exists-oldExists;
} else {
oldExists = infoPtr->number;
if (T != mail_ping(stdPtr->stream)) {
char buf[1024];
stdPtr->stream = NIL;
snprintf(buf, sizeof(buf), "%s close 1", infoPtr->cmdName);
Tcl_GlobalEval(interp, buf);
Tcl_SetResult(interp, "Lost contact with mailbox", TCL_STATIC);
Tcl_SetErrorCode(interp, "C_CLIENT", "streamdied", NULL);
return -1;
}
numNew = stdPtr->exists-oldExists;
}
if (numNew) {
sprintf(sequence, "%d:%d", stdPtr->exists-numNew+1, stdPtr->exists);
mail_fetchfast_full(stdPtr->stream, sequence, NIL);
}
infoPtr->number = stdPtr->exists;
infoPtr->recent = stdPtr->stream->recent;
for (i = 1,infoPtr->unseen=0; i <= stdPtr->stream->nmsgs; i++) {
if (!mail_elt(stdPtr->stream,i)->seen) infoPtr->unseen++;
}
return numNew;
}
/*
*----------------------------------------------------------------------
*
* Std_InsertProc --
*
* See the documentation for insertProc in ratFolder.h
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the documentation for insertProc in ratFolder.h
*
*
*----------------------------------------------------------------------
*/
static int
Std_InsertProc(RatFolderInfoPtr infoPtr, Tcl_Interp *interp, int argc,
char *argv[])
{
StdFolderInfo *stdPtr = (StdFolderInfo *) infoPtr->private;
char flags[128], date[128];
Tcl_CmdInfo cmdInfo;
Tcl_DString ds;
STRING string;
int i;
if (NIL == stdPtr->stream) {
Tcl_AppendResult(interp, "Failed to open std mailbox \"",
argv[2], "\"", (char *) NULL);
return TCL_ERROR;
}
Tcl_DStringInit(&ds);
for (i=0; i<argc; i++) {
Tcl_GetCommandInfo(interp, argv[i], &cmdInfo);
RatMessageGet(interp, (MessageInfo*)cmdInfo.objClientData,
&ds, flags, sizeof(flags), date, sizeof(date));
INIT(&string,mail_string,Tcl_DStringValue(&ds),Tcl_DStringLength(&ds));
RatPurgeFlags(flags, 1);
if (!mail_append_full(stdPtr->stream, stdPtr->stream->mailbox,
flags, date, &string)){
Tcl_SetResult(interp, "mail_append failed", TCL_STATIC);
return TCL_ERROR;
}
Tcl_DStringSetLength(&ds, 0);
if (!stdPtr->exists) {
if (T != mail_ping(stdPtr->stream)) {
char buf[1024];
Tcl_DStringFree(&ds);
snprintf(buf, sizeof(buf), "%s close", infoPtr->cmdName);
Tcl_GlobalEval(interp, buf);
Tcl_SetResult(interp, "Mailbox stream died", TCL_STATIC);
Tcl_SetErrorCode(interp, "C_CLIENT", "streamdied", NULL);
return TCL_ERROR;
}
}
}
Tcl_DStringFree(&ds);
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Std_SetFlagProc --
*
* See the documentation for setFlagProc in ratFolder.h
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the documentation for setFlagProc in ratFolder.h
*
*
*----------------------------------------------------------------------
*/
static int
Std_SetFlagProc(RatFolderInfoPtr infoPtr, Tcl_Interp *interp, int index,
RatFlag flag, int value)
{
StdFolderInfo *stdPtr = (StdFolderInfo *) infoPtr->private;
MessageInfo *msgPtr = (MessageInfo*)infoPtr->privatePtr[index];
MESSAGECACHE *cachePtr;
char sequence[8];
int wasseen;
if (!stdPtr->stream
|| stdPtr->stream->rdonly) {
return TCL_OK;
}
if (msgPtr->info[RAT_FOLDER_STATUS]) {
Tcl_DecrRefCount(msgPtr->info[RAT_FOLDER_STATUS]);
msgPtr->info[RAT_FOLDER_STATUS] = NULL;
}
cachePtr = mail_elt(stdPtr->stream, index+1);
wasseen = cachePtr->seen;
sprintf(sequence, "%d", index+1);
if (value) {
mail_setflag_full(stdPtr->stream, sequence,
flag_name[flag].imap_name, NIL);
} else {
mail_clearflag_full(stdPtr->stream, sequence,
flag_name[flag].imap_name, NIL);
}
(void)mail_fetchenvelope(stdPtr->stream, index+1);
cachePtr = mail_elt(stdPtr->stream, index+1);
switch (flag) {
case RAT_SEEN:
if (wasseen != value) {
if (wasseen) {
infoPtr->unseen++;
} else {
infoPtr->unseen--;
}
}
cachePtr->seen = value; break;
break;
case RAT_DELETED: cachePtr->deleted = value; break;
case RAT_FLAGGED: cachePtr->flagged = value; break;
case RAT_ANSWERED: cachePtr->answered = value; break;
case RAT_DRAFT: cachePtr->draft = value; break;
case RAT_RECENT: cachePtr->recent = value; break;
}
infoPtr->recent = stdPtr->stream->recent;
if (logLevel > RAT_WARN) {
Tcl_SetResult(interp, logMessage, TCL_VOLATILE);
return TCL_ERROR;
} else {
return TCL_OK;
}
}
/*
*----------------------------------------------------------------------
*
* Std_GetFlagProc --
*
* See the documentation for getFlagProc in ratFolder.h
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the documentation for getFlagProc in ratFolder.h
*
*
*----------------------------------------------------------------------
*/
static int
Std_GetFlagProc(RatFolderInfoPtr infoPtr, Tcl_Interp *interp, int index,
RatFlag flag)
{
StdFolderInfo *stdPtr = (StdFolderInfo *) infoPtr->private;
MESSAGECACHE *cachePtr;
char sequence[8];
int value = 0;
if (!stdPtr->stream) return 0;
sprintf(sequence, "%d", index+1);
logLevel = RAT_BABBLE;
(void)mail_fetchstructure_full(stdPtr->stream, index+1, NIL, NIL);
cachePtr = mail_elt(stdPtr->stream, index+1);
switch (flag) {
case RAT_SEEN: value = cachePtr->seen; break;
case RAT_DELETED: value = cachePtr->deleted; break;
case RAT_FLAGGED: value = cachePtr->flagged; break;
case RAT_ANSWERED: value = cachePtr->answered; break;
case RAT_DRAFT: value = cachePtr->draft; break;
case RAT_RECENT: value = cachePtr->recent; break;
}
return value;
}
/*
*----------------------------------------------------------------------
*
* Std_InfoProc --
*
* See the documentation for infoProc in ratFolder.h
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the documentation for infoProc in ratFolder.h
*
*
*----------------------------------------------------------------------
*/
Tcl_Obj*
Std_InfoProc(Tcl_Interp *interp, ClientData clientData, RatFolderInfoType type,
int index)
{
RatFolderInfo *infoPtr = (RatFolderInfo*)clientData;
return Std_GetInfoProc(interp, (ClientData)infoPtr->privatePtr[index],
type, 0);
}
/*
*----------------------------------------------------------------------
*
* Std_SetInfoProc --
*
* See the documentation for setInfoProc in ratFolder.h
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the documentation for setInfoProc in ratFolder.h
*
*
*----------------------------------------------------------------------
*/
void
Std_SetInfoProc(Tcl_Interp *interp, ClientData clientData,
RatFolderInfoType type, int index, Tcl_Obj *oPtr)
{
RatFolderInfo *infoPtr = (RatFolderInfo*)clientData;
MessageInfo *msgPtr = (MessageInfo*)infoPtr->privatePtr[index];
if (msgPtr->info[type]) {
Tcl_DecrRefCount(msgPtr->info[type]);
}
msgPtr->info[type] = oPtr;
if (oPtr) {
Tcl_IncrRefCount(oPtr);
}
}
/*
*----------------------------------------------------------------------
*
* Std_CreateProc --
*
* See the documentation for createProc in ratFolder.h
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the documentation for createProc in ratFolder.h
*
*
*----------------------------------------------------------------------
*/
char*
Std_CreateProc(RatFolderInfoPtr infoPtr, Tcl_Interp *interp, int index)
{
StdFolderInfo *stdPtr = (StdFolderInfo *) infoPtr->private;
return RatStdMessageCreate(interp, infoPtr, stdPtr->stream, index);
}
/*
*----------------------------------------------------------------------
*
* StdImportCmd --
*
* Import folders (via mm_list)
*
* Results:
* The folders found are returned as a list
*
* Side effects:
* RatLogin may be called.
*
*
*----------------------------------------------------------------------
*/
static int
StdImportCmd(ClientData dummy, Tcl_Interp *interp, int objc,
Tcl_Obj *const objv[])
{
Tcl_Obj *oPtr, **iobjv, **bobjv, *origPtr;
int iobjc, bobjc, subscribed, i, lastId, id;
char *spec, path[1024], buf[1024];
MAILSTREAM *stream = NULL;
/*
* Check arguments
* check that we got one
* check that it is is a folder definition id and that it
* points to a correct import-folder.
*/
if (objc != 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetString(objv[0]), " id\"", (char *) NULL);
return TCL_ERROR;
}
origPtr = Tcl_GetVar2Ex(interp, "vFolderDef", Tcl_GetString(objv[1]),
TCL_GLOBAL_ONLY);
if (TCL_OK != Tcl_GetIntFromObj(interp, objv[1], &id)
|| NULL == origPtr
|| TCL_OK != Tcl_ListObjGetElements(interp, origPtr, &iobjc, &iobjv)
|| 6 != iobjc
|| strcmp("import", Tcl_GetString(iobjv[1]))
|| TCL_OK != Tcl_ListObjGetElements(interp, iobjv[3], &bobjc, &bobjv)){
Tcl_AppendResult(interp, "Bad folder id specified \"",
Tcl_GetString(objv[1]), "\"", (char *) NULL);
return TCL_ERROR;
}
spec = RatGetFolderSpec(interp, iobjv[3]);
logIgnore++;
stream = Std_StreamOpen(interp, spec, OP_HALFOPEN, NULL, NULL);
logIgnore--;
/*
* See if we only want subscribed folders
*/
Tcl_ListObjLength(interp, iobjv[2], &i);
for (subscribed = 0, i -= 2; i>=0; i -= 2) {
Tcl_ListObjIndex(interp, iobjv[2], i, &oPtr);
if (!strcmp("subscribed", Tcl_GetString(oPtr))) {
Tcl_ListObjIndex(interp, iobjv[2], i+1, &oPtr);
Tcl_GetIntFromObj(interp, oPtr, &subscribed);
break;
}
}
/*
* Run search
* This builds a list of all found folders in mailboxListPtr
* First we run a dummy-search to get the hierarchy delimiter
*/
if ((mailboxSearchBase = strchr(spec, '}'))) {
mailboxSearchBase++;
} else {
mailboxSearchBase = spec;
}
mail_list(stream, "", spec);
strlcpy(buf, spec, sizeof(buf));
if (*mailboxSearchBase
&& lastDelimiter[0] != mailboxSearchBase[strlen(mailboxSearchBase)-1]
&& lastDelimiter[0] != Tcl_GetString(iobjv[4])[0]) {
strlcat(buf, lastDelimiter, sizeof(buf));
}
strlcat(buf, Tcl_GetString(iobjv[4]), sizeof(buf));
if (subscribed) {
mail_lsub(stream, "", buf);
} else {
mail_list(stream, "", buf);
}
if (stream) {
Std_StreamClose(interp, stream);
}
/*
* Compare list in mailboxListPtr with already existing list
*/
if ('{' == spec[0]) {
strlcpy(path, strchr(spec, '}')+1, sizeof(path));
} else {
strlcpy(path, spec, sizeof(path));
}
if ('*' == path[strlen(path)-1] || '%' == path[strlen(path)-1]) {
path[strlen(path)-1] = '\0';
}
if (mailboxListPtr && path[strlen(path)-1] == mailboxListPtr->delimiter) {
path[strlen(path)-1] = '\0';
}
snprintf(buf, sizeof(buf),
"lindex [lsort -integer [array names vFolderDef]] end");
Tcl_GlobalEval(interp, buf);
lastId = atoi(Tcl_GetStringResult(interp));
StdImportBuildResult(interp, mailboxListPtr, &lastId, id,
bobjc, bobjv);
mailboxListPtr = NULL;
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* StdImportBuildResult --
*
* Recursive function which parses the import result into folders
*
* Results:
* None
*
* Side effects:
* The vFolderDef array may be modified
*
*
*----------------------------------------------------------------------
*/
typedef struct {
int id;
int objc;
Tcl_Obj **objv;
} Mbox;
static void
StdImportBuildResult(Tcl_Interp *interp, Mailbox *mPtr, int *lastId,
int id, int templatec, Tcl_Obj **templatev)
{
Tcl_Obj **objv, *oPtr, *lPtr, *iPtr, *idList;
Mailbox *nPtr;
Mbox *mbox_in, *mbox_out = NULL;
int i, num_mbox_in, mbox_out_alloc = 0, count, changed = 0,
disconnected = 0, listpos;
char buf[32];
if (!strcmp("dis", Tcl_GetString(templatev[1]))) {
disconnected = 1;
}
/*
* Split list of ids and create list of definitions
*/
snprintf(buf, sizeof(buf), "%d", id);
oPtr = Tcl_GetVar2Ex(interp, "vFolderDef", buf, TCL_GLOBAL_ONLY);
Tcl_ListObjIndex(interp, oPtr, 1, &iPtr);
if (!strcmp("struct", Tcl_GetString(iPtr))) {
listpos = 3;
} else {
listpos = 5;
}
Tcl_ListObjIndex(interp, oPtr, listpos, &idList);
Tcl_ListObjGetElements(interp, idList, &num_mbox_in, &objv);
mbox_in = (Mbox*)ckalloc(sizeof(Mbox)*num_mbox_in);
for (i=0; i<num_mbox_in; i++) {
Tcl_GetIntFromObj(interp, objv[i], &mbox_in[i].id);
oPtr = Tcl_GetVar2Ex(interp, "vFolderDef", Tcl_GetString(objv[i]),
TCL_GLOBAL_ONLY);
Tcl_ListObjGetElements(interp, oPtr,&mbox_in[i].objc,&mbox_in[i].objv);
}
/*
* Loop over found mailboxes on this level.
* For each one start by locating it in the list.
* If found, then move to outlist
* Finally if it is a struct, then check list of contained folders
*/
for (count = 0; mPtr; mPtr = nPtr) {
if (count+2 >= mbox_out_alloc) {
mbox_out_alloc += 100;
mbox_out = (Mbox*)ckrealloc(mbox_out, mbox_out_alloc*sizeof(Mbox));
}
for (i=0; i<num_mbox_in; i++) {
if (mbox_in[i].id != 0
&& !strcmp(mPtr->name, Tcl_GetString(mbox_in[i].objv[0]))
&& ((!strcmp("struct", Tcl_GetString(mbox_in[i].objv[1]))
&& 0 == (LATT_NOINFERIORS & mPtr->attributes))
|| ((strcmp("struct", Tcl_GetString(mbox_in[i].objv[1]))
&& 0 != (LATT_NOINFERIORS & mPtr->attributes))))) {
break;
}
}
if (i == num_mbox_in) { /* Not found => new */
changed = 1;
if (0 == (mPtr->attributes & LATT_NOSELECT)) {
/* Create ordinary folder */
mbox_out[count].id = ++(*lastId);
lPtr = Tcl_NewObj();
Tcl_ListObjAppendElement(interp, lPtr,
Tcl_NewStringObj(mPtr->name, -1));
Tcl_ListObjAppendElement(interp, lPtr, templatev[1]);
Tcl_ListObjAppendElement(interp, lPtr, templatev[2]);
if (5 == templatec) {
Tcl_ListObjAppendElement(interp, lPtr, templatev[3]);
}
Tcl_ListObjAppendElement(interp, lPtr,
Tcl_NewStringObj(mPtr->folder, -1));
snprintf(buf, sizeof(buf), "%d", mbox_out[count].id);
Tcl_SetVar2Ex(interp, "vFolderDef", buf, lPtr,TCL_GLOBAL_ONLY);
Tcl_ListObjGetElements(interp, lPtr, &mbox_out[count].objc,
&mbox_out[count].objv);
if (disconnected) {
RatDisManageFolder(interp, RAT_MGMT_CREATE, lPtr);
}
count++;
}
if (0 == (mPtr->attributes & LATT_NOINFERIORS)) {
/* Create struct */
mbox_out[count].id = ++(*lastId);
lPtr = Tcl_NewObj();
Tcl_ListObjAppendElement(interp, lPtr,
Tcl_NewStringObj(mPtr->name, -1));
Tcl_ListObjAppendElement(interp, lPtr,
Tcl_NewStringObj("struct", 6));
Tcl_ListObjAppendElement(interp, lPtr, Tcl_NewObj());
Tcl_ListObjAppendElement(interp, lPtr, Tcl_NewObj());
snprintf(buf, sizeof(buf), "%d", mbox_out[count].id);
Tcl_SetVar2Ex(interp, "vFolderDef", buf, lPtr,TCL_GLOBAL_ONLY);
Tcl_ListObjGetElements(interp, lPtr, &mbox_out[count].objc,
&mbox_out[count].objv);
count++;
}
} else { /* Found => old */
mbox_out[count].id = mbox_in[i].id;
mbox_out[count].objc = mbox_in[i].objc;
mbox_out[count].objv = mbox_in[i].objv;
mbox_in[i].id = 0;
count++;
}
if (mPtr->child) {
StdImportBuildResult(interp, mPtr->child, lastId,
mbox_out[count-1].id, templatec, templatev);
}
nPtr = mPtr->next;
ckfree(mPtr);
}
for (i=0; i<num_mbox_in; i++) {
if (0 != mbox_in[i].id) {
changed = 1;
snprintf(buf, sizeof(buf), "%d", mbox_in[i].id);
Tcl_UnsetVar2(interp, "vFolderDef", buf, TCL_GLOBAL_ONLY);
}
}
/* Build result */
if (changed) {
oPtr = Tcl_NewObj();
for (i=0; i<count; i++) {
Tcl_ListObjAppendElement(interp, oPtr,
Tcl_NewIntObj(mbox_out[i].id));
}
/* Change vFolderDef */
snprintf(buf, sizeof(buf), "%d", id);
lPtr = Tcl_GetVar2Ex(interp, "vFolderDef", buf, TCL_GLOBAL_ONLY);
lPtr = Tcl_DuplicateObj(lPtr);
Tcl_ListObjReplace(interp, lPtr, listpos, 1, 1, &oPtr);
Tcl_SetVar2Ex(interp, "vFolderDef", buf, lPtr, TCL_GLOBAL_ONLY);
} else {
oPtr = idList;
}
}
/*
*----------------------------------------------------------------------
*
* CloseConnection --
*
* Closes a connection.
*
* Results:
* None.
*
* Side effects:
* The connection list is modified.
*
*
*----------------------------------------------------------------------
*/
static void
CloseConnection(ClientData clientData)
{
Connection **connPtrPtr, *connPtr = (Connection*)clientData;
Tcl_DeleteTimerHandler(connPtr->token);
logIgnore++;
mail_close_full(connPtr->stream, NIL);
logIgnore--;
for (connPtrPtr = &connListPtr; *connPtrPtr != connPtr;
connPtrPtr = &(*connPtrPtr)->next);
*connPtrPtr = connPtr->next;
ckfree(connPtr);
}
/*
*----------------------------------------------------------------------
*
* AppendToIMAP --
*
* Append the given message to an IMAP folder
*
* Results:
* None.
*
* Side effects:
* The specified folder will be modified
*
*
*----------------------------------------------------------------------
*/
void
AppendToIMAP(Tcl_Interp *interp, const char *mailboxSpec, const char *flags,
const char *date, const char *msg, int length)
{
char *mailbox;
MAILSTREAM *stream;
STRING msgString;
int error;
mailbox = RatLindex(interp, mailboxSpec, 0);
if (NULL == (stream = Std_StreamOpen(interp, mailbox, 0, &error, NULL))) {
return;
}
INIT(&msgString, mail_string, (char*)msg, length);
mail_append_full(stream, (char*)mailbox, (char*)flags, (char*)date,
&msgString);
Std_StreamClose(interp, stream);
}
/*
*----------------------------------------------------------------------
*
* FindConn --
*
* Find the connection pointer for the stream
*
* Results:
* A connection pointer (or NULL)
*
* Side effects:
* None
*
*
*----------------------------------------------------------------------
*/
static Connection*
FindConn(MAILSTREAM *stream)
{
Connection *connPtr;
for (connPtr=connListPtr;
connPtr && connPtr->stream != stream;
connPtr=connPtr->next);
return connPtr;
}
/*
*----------------------------------------------------------------------
*
* Handle* --
*
* Handle events from mailbox
*
* Results:
* None
*
* Side effects:
* None
*
*
*----------------------------------------------------------------------
*/
static void
Std_HandleExists(void *state, unsigned long nmsg)
{
StdFolderInfo *stdPtr = (StdFolderInfo *) state;
stdPtr->exists = nmsg;
}
static void
Std_HandleExpunged(void *state, unsigned long index)
{
StdFolderInfo *stdPtr = (StdFolderInfo *) state;
stdPtr->exists--;
}
/*
*----------------------------------------------------------------------
*
* Std_GetType --
*
* Determines the type of folder from a mailbox stream name
*
* Results:
* The type
*
* Side effects:
* None
*
*
*----------------------------------------------------------------------
*/
static RatStdFolderType
Std_GetType(const char *spec)
{
const char *c;
RatStdFolderType type;
if ('{' == spec[0]) {
type = RAT_IMAP;
for (c=spec+1; *c != '}'; c++) {
if ('/' == c[0]
&& 'p' == c[1] && 'o' == c[2] && 'p' == c[3] && '3' == c[4]) {
type = RAT_POP;
break;
}
}
} else if ('#' == spec[0] && 'm' == spec[1] && 'h' == spec[2]) {
type = RAT_MH;
} else {
type = RAT_UNIX;
}
return type;
}
/*
*----------------------------------------------------------------------
*
* RatStdManageFolder --
*
* Create or delete folders on disk ro remote server
*
* Results:
* A standard tcl result
*
* Side effects:
* None
*
*
*----------------------------------------------------------------------
*/
int
RatStdManageFolder(Tcl_Interp *interp, RatManagementAction op, Tcl_Obj *fPtr)
{
MAILSTREAM *stream;
struct stat sbuf;
char *spec;
Tcl_Obj *oPtr;
int result, error;
spec = RatGetFolderSpec(interp, fPtr);
if ('{' == spec[0]) {
stream = Std_StreamOpen(interp, spec, OP_HALFOPEN, &error, NULL);
if (!stream) {
Tcl_SetResult(interp,"Failed to open stream to server",TCL_STATIC);
return TCL_ERROR;
}
} else {
stream = NULL;
}
if (op == RAT_MGMT_CREATE) {
if ('/' == spec[0]) {
/*
* Since this is a file folder we check if the file already
* exists, and do nothing if that is the case. This is to
* avoid getting an error message
*/
if (0 == stat(spec, &sbuf)) {
return TCL_OK;
}
}
result = mail_create(stream, spec);
} else {
logIgnore++;
(void)mail_delete(stream, spec);
logIgnore--;
result = 1;
}
if (stream) {
Std_StreamClose(interp, stream);
}
Tcl_ListObjIndex(interp, fPtr, 1, &oPtr);
if (result && !strcmp("dis", Tcl_GetString(oPtr))) {
RatDisManageFolder(interp, op, fPtr);
}
if (result) {
return TCL_OK;
} else {
Tcl_SetResult(interp, "Failed to create folder", TCL_STATIC);
return TCL_ERROR;
}
}
/*
*----------------------------------------------------------------------
*
* RatStdCheckNet --
*
* Check if we have any network connections which are active
* and if not go offline.
*
* Results:
* None
*
* Side effects:
* None
*
*
*----------------------------------------------------------------------
*/
void RatStdCheckNet(Tcl_Interp *interp)
{
Connection *connPtr;
char buf[64];
int existsnetok = 0;
for (connPtr = connListPtr; connPtr; connPtr = connPtr->next) {
if (connPtr->isnet
&& (!connPtr->errorFlagPtr || 0 == *connPtr->errorFlagPtr)) {
existsnetok = 1;
}
}
if (0 == existsnetok) {
strlcpy(buf, "SetOnlineStatus 0", sizeof(buf));
Tcl_Eval(interp, buf);
}
}
/*
*----------------------------------------------------------------------
*
* mm_*
*
* The functions below are called from the C-client library. They
* are docuemnted in Internal.DOC.
*
*----------------------------------------------------------------------
*/
void mm_searched (MAILSTREAM *stream,unsigned long number)
{
if (searchResultSize == searchResultNum) {
searchResultSize += 1024;
searchResultPtr = (long*)ckrealloc(searchResultPtr,
searchResultSize*sizeof(long));
}
searchResultPtr[searchResultNum++] = number;
}
void mm_exists (MAILSTREAM *stream, unsigned long nmsgs)
{
Connection *connPtr = FindConn(stream);
if (connPtr && connPtr->handlers && connPtr->handlers->exists) {
(*connPtr->handlers->exists)(connPtr->handlers->state, nmsgs);
}
}
void mm_expunged (MAILSTREAM *stream, unsigned long index)
{
Connection *connPtr = FindConn(stream);
if (connPtr && connPtr->handlers && connPtr->handlers->expunged) {
(*connPtr->handlers->expunged)(connPtr->handlers->state, index);
}
}
void mm_mailbox (char *string)
{
}
void mm_bboard (char *string)
{
}
void mm_notify (MAILSTREAM *stream,char *string,long errflg)
{
if (errflg == BYE) {
Connection *connPtr = FindConn(stream);
if (connPtr && connPtr->errorFlagPtr) {
*connPtr->errorFlagPtr = 1;
}
}
}
void mm_log (char *string,long errflg)
{
switch(errflg) {
case NIL: logLevel = RAT_BABBLE; break;
case PARSE: logLevel = RAT_PARSE; break;
case WARN: logLevel = RAT_WARN; break;
case BYE: logLevel = RAT_FATAL; break;
case ERROR: /* fallthrough */
default: logLevel = RAT_ERROR; break;
}
ckfree(logMessage);
logMessage = cpystr(string);
if (logIgnore) {
return;
}
RatLog(timerInterp, logLevel, string, RATLOG_NOWAIT);
}
void mm_dlog (char *string)
{
CONST84 char *filename;
if (!debugFile
&& NULL != (filename = RatGetPathOption(timerInterp, "debug_file"))) {
debugFile = fopen(filename, "a");
if (debugFile) {
fchmod(fileno(debugFile), 0600);
}
}
if (debugFile) {
fprintf(debugFile, "%s\n", string);
fflush(debugFile);
}
RatLog(timerInterp, RAT_BABBLE, string, RATLOG_TIME);
}
void mm_login (NETMBX *mbPtr, char *user, char *pwd, long trial)
{
char *pw;
int objc;
Tcl_Obj *oPtr, **objv;
/*
* Check for cached entry
*/
if ((pw = RatGetCachedPassword(timerInterp, loginSpec))) {
strlcpy(user, mbPtr->user, MAILTMPLEN);
strlcpy(pwd, pw, MAILTMPLEN);
return;
}
oPtr = Tcl_NewObj();
Tcl_ListObjAppendElement(timerInterp, oPtr,
Tcl_NewStringObj("RatLogin", -1));
Tcl_ListObjAppendElement(timerInterp, oPtr,
Tcl_NewStringObj(mbPtr->host, -1));
Tcl_ListObjAppendElement(timerInterp, oPtr,
Tcl_NewLongObj(trial));
Tcl_ListObjAppendElement(timerInterp, oPtr,
Tcl_NewStringObj(mbPtr->user, -1));
Tcl_ListObjAppendElement(timerInterp, oPtr,
Tcl_NewStringObj(mbPtr->service,-1));
Tcl_ListObjAppendElement(timerInterp, oPtr, Tcl_NewLongObj(mbPtr->port));
if (TCL_OK != Tcl_EvalObj(timerInterp, oPtr)
|| NULL == (oPtr = Tcl_GetObjResult(timerInterp))
|| TCL_OK != Tcl_ListObjGetElements(timerInterp, oPtr, &objc, &objv)
|| 3 != objc) {
pwd[0] = '\0';
return;
}
strlcpy(user, Tcl_GetString(objv[0]), MAILTMPLEN);
strlcpy(pwd, Tcl_GetString(objv[1]), MAILTMPLEN);
if ('\0' != user[0]) {
strlcpy(loginPassword, Tcl_GetString(objv[1]), MAILTMPLEN);
Tcl_GetBooleanFromObj(timerInterp, objv[2], &loginStore);
} else {
/* User pressed cancel */
loginStore = 0;
logIgnore++;
}
}
void mm_critical (MAILSTREAM *stream)
{
}
void mm_nocritical (MAILSTREAM *stream)
{
}
long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
{
char buf[64];
sprintf(buf, "Disk error: %ld", errcode);
RatLog(timerInterp, RAT_FATAL, buf, RATLOG_TIME);
return 1;
}
void mm_fatal (char *string)
{
RatLog(timerInterp, RAT_FATAL, string, RATLOG_TIME);
}
void mm_flags (MAILSTREAM *stream,unsigned long number)
{
}
void
mm_list(MAILSTREAM *stream, int delimiter, char *spec, long attributes)
{
Mailbox **mPtrPtr = &mailboxListPtr, *nPtr;
char *name, *folder, *s, *e;
int do_decode = 0;
Tcl_DString *encoded;
lastDelimiter[0] = delimiter;
if ('{' == spec[0]) {
for (s=spec; *s && 0 == (*s & 0x80); s++);
if (!*s) {
do_decode = 1;
}
}
/*
* Create new Mailbox structure
*/
if ((folder = strchr(spec, '}'))) {
folder++;
} else {
folder = spec;
}
if (delimiter && (NULL != (name = strrchr(folder, delimiter)))) {
name++;
} else {
name = folder;
}
if (!*name && !(attributes & LATT_NOSELECT)) {
return;
}
/*
* First find the right level
*/
if (!strncmp(mailboxSearchBase, folder, strlen(mailboxSearchBase))) {
s = folder+strlen(mailboxSearchBase);
} else {
s = folder;
}
for (; delimiter && (e = strchr(s, delimiter));
*e = delimiter, s = e+1) {
*e = '\0';
if (!strlen(s)) {
continue;
}
while (*mPtrPtr && 0 > strcmp((*mPtrPtr)->name, s)) {
mPtrPtr = &(*mPtrPtr)->next;
}
if (!*mPtrPtr || strcmp((*mPtrPtr)->name, s)) {
nPtr = (Mailbox*)ckalloc(sizeof(Mailbox)+strlen(s)*3+1);
nPtr->name = (char*)nPtr+sizeof(Mailbox);
strcpy(nPtr->name, (do_decode ? RatMutf7toUtf8(s) : s));
nPtr->folder = NULL;
nPtr->attributes = LATT_NOSELECT;
nPtr->next = *mPtrPtr;
nPtr->child = NULL;
*mPtrPtr = nPtr;
mPtrPtr = &nPtr->child;
} else {
mPtrPtr = &(*mPtrPtr)->child;
}
}
if (attributes & LATT_NOSELECT) {
return;
}
/*
* Find location and link it
*/
while (*mPtrPtr && 0 > strcmp((*mPtrPtr)->name, name)) {
mPtrPtr = &(*mPtrPtr)->next;
}
/*
* Ignore duplicates
*/
encoded = RatEncodeQP(folder);
if (*mPtrPtr && (*mPtrPtr)->folder
&& !strcmp((*mPtrPtr)->folder, Tcl_DStringValue(encoded))
&& (*mPtrPtr)->attributes == attributes) {
Tcl_DStringFree(encoded);
ckfree(encoded);
return;
}
/*
* Create actual folder entry
*/
nPtr = (Mailbox*)ckalloc(
sizeof(Mailbox) + strlen(name)*3 + Tcl_DStringLength(encoded) + 2);
nPtr->name = (char*)nPtr+sizeof(Mailbox);
strcpy(nPtr->name, (do_decode ? RatMutf7toUtf8(name) : name));
nPtr->folder = nPtr->name+strlen(nPtr->name)+1;
strcpy(nPtr->folder, Tcl_DStringValue(encoded));
nPtr->attributes = attributes;
nPtr->delimiter = delimiter;
nPtr->next = *mPtrPtr;
nPtr->child = NULL;
*mPtrPtr = nPtr;
Tcl_DStringFree(encoded);
ckfree(encoded);
}
void
mm_lsub (MAILSTREAM *stream, int delimiter, char *name, long attributes)
{
mm_list(stream, delimiter, name, attributes | LATT_NOINFERIORS);
}
void mm_status (MAILSTREAM *stream, char *mailbox, MAILSTATUS *status)
{
memcpy(&stdStatus, status, sizeof(MAILSTATUS));
}
#ifdef MEM_DEBUG
void ratStdFolderCleanup()
{
ckfree(logMessage);
}
#endif /* MEM_DEBUG */
syntax highlighted by Code2HTML, v. 0.9.1