/*
* ratStdMessage.c --
*
* This file contains code which implements standard c-client messages.
*
* 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"
/*
* The ClientData for each message entity
*/
typedef struct StdMessageInfo {
MAILSTREAM *stream;
MESSAGECACHE *eltPtr;
ENVELOPE *envPtr;
BODY *bodyPtr;
RatStdFolderType type;
char *spec;
} StdMessageInfo;
/*
* The ClientData for each bodypart entity
*/
typedef struct StdBodyInfo {
char *section;
} StdBodyInfo;
/*
* The number of message entities created. This is used to create new
* unique command names.
*/
static int numStdMessages = 0;
#ifdef MEM_DEBUG
static char *mem_header = NULL;
#endif /* MEM_DEBUG */
/*
*----------------------------------------------------------------------
*
* RatStdMessagesInit --
*
* Initializes the given MessageProcInfo entry for a c-client message
*
* Results:
* None.
*
* Side effects:
* The given MessageProcInfo is initialized.
*
*
*----------------------------------------------------------------------
*/
void
RatStdMessagesInit(MessageProcInfo *messageProcInfoPtr)
{
messageProcInfoPtr->getHeadersProc = Std_GetHeadersProc;
messageProcInfoPtr->getEnvelopeProc = Std_GetEnvelopeProc;
messageProcInfoPtr->getInfoProc = Std_GetInfoProc;
messageProcInfoPtr->createBodyProc = Std_CreateBodyProc;
messageProcInfoPtr->fetchTextProc = Std_FetchTextProc;
messageProcInfoPtr->envelopeProc = Std_EnvelopeProc;
messageProcInfoPtr->msgDeleteProc = Std_MsgDeleteProc;
messageProcInfoPtr->makeChildrenProc = Std_MakeChildrenProc;
messageProcInfoPtr->fetchBodyProc = Std_FetchBodyProc;
messageProcInfoPtr->bodyDeleteProc = Std_BodyDeleteProc;
messageProcInfoPtr->getInternalDateProc = Std_GetInternalDateProc;
}
/*
*----------------------------------------------------------------------
*
* RatStdMessageCreate --
*
* Creates a std message entity
*
* Results:
* The name of the new message entity.
*
* Side effects:
* The message's long cache entry is locked until the message is
* deleted.
*
*
*----------------------------------------------------------------------
*/
char*
RatStdMessageCreate(Tcl_Interp *interp, RatFolderInfoPtr folderInfoPtr,
MAILSTREAM *stream, int msgNo)
{
MessageInfo *msgPtr = (MessageInfo*)folderInfoPtr->privatePtr[msgNo];
StdMessageInfo *stdMsgPtr = (StdMessageInfo*)msgPtr->clientData;
stdMsgPtr->envPtr =
mail_fetchstructure_full(stream, msgNo+1, &stdMsgPtr->bodyPtr, NIL);
stdMsgPtr->eltPtr = mail_elt(stream, msgNo+1);
stdMsgPtr->eltPtr->lockcount++;
stdMsgPtr->spec = cpystr(stream->mailbox);
sprintf(msgPtr->name, "RatStdMsg%d", numStdMessages++);
Tcl_CreateObjCommand(interp, msgPtr->name, RatMessageCmd,
(ClientData)msgPtr, NULL);
return msgPtr->name;
}
/*
*----------------------------------------------------------------------
*
* RatStdEasyCopyingOK --
*
* Check if we can lets c-client handle the copying of this message
*
* Results:
* A boolean which says if it is OK or not.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
RatStdEasyCopyingOK(Tcl_Interp *interp, MessageInfo *msgPtr, Tcl_Obj *defPtr)
{
StdMessageInfo *stdMsgPtr = (StdMessageInfo*)msgPtr->clientData;
Tcl_Obj **objv;
int objc;
Tcl_ListObjGetElements(interp, defPtr, &objc, &objv);
switch (stdMsgPtr->type) {
case RAT_DIS:
return 0;
case RAT_MBX:
return 0;
case RAT_UNIX:
return !strcasecmp(Tcl_GetString(objv[1]), "file");
case RAT_MH:
return !strcasecmp(Tcl_GetString(objv[1]), "mh");
case RAT_POP:
return 0;
case RAT_IMAP:
if (strcasecmp(Tcl_GetString(objv[1]), "imap")) {
return 0;
}
return !strcmp(stdMsgPtr->spec, RatGetFolderSpec(interp, defPtr));
}
return 0;
}
/*
*----------------------------------------------------------------------
*
* RatStdMessageCopy --
*
* Copy a message to another c-client folder.
*
* Results:
* A boolean which says if it went OK or not.
*
* Side effects:
* The destination folder is modified.
*
*
*----------------------------------------------------------------------
*/
int
RatStdMessageCopy (Tcl_Interp *interp, MessageInfo *msgPtr, char *destination)
{
StdMessageInfo *stdMsgPtr = (StdMessageInfo*)msgPtr->clientData;
int flagged = stdMsgPtr->eltPtr->flagged;
int deleted = stdMsgPtr->eltPtr->deleted;
char *cPtr, seq[16];
int r = TCL_ERROR;
sprintf(seq, "%d", msgPtr->msgNo+1);
if (flagged) {
mail_clearflag(stdMsgPtr->stream, seq,
flag_name[RAT_FLAGGED].imap_name);
}
if (deleted) {
mail_clearflag(stdMsgPtr->stream, seq,
flag_name[RAT_DELETED].imap_name);
}
switch (stdMsgPtr->type) {
case RAT_UNIX: /* fallthrough */
case RAT_MBX: /* fallthrough */
case RAT_DIS: /* fallthrough */
case RAT_MH: /* fallthrough */
case RAT_POP: /* fallthrough */
if (T == mail_copy_full(stdMsgPtr->stream, seq, destination, 0)) {
r = TCL_OK;
}
break;
case RAT_IMAP:
cPtr = strchr(destination, '}');
if (cPtr && mail_copy_full(stdMsgPtr->stream, seq, &cPtr[1], 0)) {
r = TCL_OK;
}
break;
}
if (flagged) {
mail_setflag(stdMsgPtr->stream, seq, flag_name[RAT_FLAGGED].imap_name);
}
if (deleted) {
mail_setflag(stdMsgPtr->stream, seq, flag_name[RAT_DELETED].imap_name);
}
return r;
}
/*
*----------------------------------------------------------------------
*
* Std_GetHeadersProc --
*
* See ratFolder.h
*
*----------------------------------------------------------------------
*/
char*
Std_GetHeadersProc(Tcl_Interp *interp, MessageInfo *msgPtr)
{
StdMessageInfo *stdMsgPtr = (StdMessageInfo*)msgPtr->clientData;
static char *header = NULL;
static int headerSize = 0;
unsigned long length;
char *fetchedHeader = mail_fetchheader_full(stdMsgPtr->stream,
msgPtr->msgNo+1, NIL, &length, NIL);
if (length > 2 && fetchedHeader[length-3] == '\n') {
length -= 2;
}
if (length+64 > headerSize) {
headerSize = length+64;
header = (char*)ckrealloc(header, headerSize);
}
memmove(header, fetchedHeader, length);
header[length] = '\0';
if (stdMsgPtr->eltPtr->seen) {
strcpy(&header[length], "Status: RO\r\n");
length += strlen(&header[length]);
}
if (stdMsgPtr->eltPtr->answered) {
strcpy(&header[length], "X-Status: A\r\n");
length += strlen(&header[length]);
}
#ifdef MEM_DEBUG
mem_header = header;
#endif /* MEM_DEBUG */
return header;
}
/*
*----------------------------------------------------------------------
*
* Std_GetEnvelopeProc --
*
* See ratFolder.h
*
*----------------------------------------------------------------------
*/
char*
Std_GetEnvelopeProc(Tcl_Interp *interp, MessageInfo *msgPtr)
{
static char buf[1024];
ADDRESS *adrPtr;
time_t date;
struct tm tm, *tmPtr;
StdMessageInfo *stdMsgPtr = (StdMessageInfo*)msgPtr->clientData;
if (stdMsgPtr->envPtr->return_path) {
adrPtr = stdMsgPtr->envPtr->sender;
} else if (stdMsgPtr->envPtr->sender) {
adrPtr = stdMsgPtr->envPtr->sender;
} else {
adrPtr = stdMsgPtr->envPtr->from;
}
if (adrPtr && RatAddressSize(adrPtr, 0) < sizeof(buf)-6) {
strlcpy(buf, "From ", sizeof(buf));
rfc822_address(buf+5, adrPtr);
} else {
strlcpy(buf, "From unkown", sizeof(buf));
}
tm.tm_sec = stdMsgPtr->eltPtr->seconds;
tm.tm_min = stdMsgPtr->eltPtr->minutes;
tm.tm_hour = stdMsgPtr->eltPtr->hours;
tm.tm_mday = stdMsgPtr->eltPtr->day;
tm.tm_mon = stdMsgPtr->eltPtr->month - 1;
tm.tm_year = stdMsgPtr->eltPtr->year+69;
tm.tm_wday = 0;
tm.tm_yday = 0;
tm.tm_isdst = -1;
date = (int)mktime(&tm);
tmPtr = gmtime(&date);
sprintf(buf + strlen(buf), " %s %s %2d %02d:%02d GMT %04d\n",
dayName[tmPtr->tm_wday], monthName[tmPtr->tm_mon],
tmPtr->tm_mday, tmPtr->tm_hour, tmPtr->tm_min,tmPtr->tm_year+1900);
return buf;
}
/*
*----------------------------------------------------------------------
*
* Std_CreateBodyProc --
*
* See ratFolder.h
*
*----------------------------------------------------------------------
*/
BodyInfo*
Std_CreateBodyProc(Tcl_Interp *interp, MessageInfo *msgPtr)
{
StdMessageInfo *stdMsgPtr = (StdMessageInfo*)msgPtr->clientData;
StdBodyInfo *stdBodyInfoPtr = (StdBodyInfo*)ckalloc(sizeof(StdBodyInfo));
msgPtr->bodyInfoPtr = CreateBodyInfo(msgPtr);
msgPtr->bodyInfoPtr->bodyPtr = stdMsgPtr->bodyPtr;
msgPtr->bodyInfoPtr->clientData = (ClientData)stdBodyInfoPtr;
if (TYPEMULTIPART == msgPtr->bodyInfoPtr->bodyPtr->type) {
stdBodyInfoPtr->section = NULL;
} else {
stdBodyInfoPtr->section = cpystr("1");
}
return msgPtr->bodyInfoPtr;
}
/*
*----------------------------------------------------------------------
*
* Std_FetchTextProc --
*
* See ratFolder.h
*
*----------------------------------------------------------------------
*/
char*
Std_FetchTextProc(Tcl_Interp *interp, MessageInfo *msgPtr)
{
StdMessageInfo *stdMsgPtr = (StdMessageInfo*)msgPtr->clientData;
return mail_fetchtext_full(stdMsgPtr->stream, msgPtr->msgNo+1, NIL, NIL);
}
/*
*----------------------------------------------------------------------
*
* Std_EnvelopeProc --
*
* See ratFolder.h
*
*----------------------------------------------------------------------
*/
ENVELOPE*
Std_EnvelopeProc(MessageInfo *msgPtr)
{
return ((StdMessageInfo*)msgPtr->clientData)->envPtr;
}
/*
*----------------------------------------------------------------------
*
* Std_MsgDeleteProc --
*
* See ratFolder.h
*
*----------------------------------------------------------------------
*/
void
Std_MsgDeleteProc(MessageInfo *msgPtr)
{
RatFolderInfo *infoPtr = msgPtr->folderInfoPtr;
StdMessageInfo *stdMsgPtr = (StdMessageInfo*)msgPtr->clientData;
infoPtr->privatePtr[msgPtr->msgNo] = NULL;
stdMsgPtr->eltPtr->lockcount--;
ckfree(stdMsgPtr->spec);
ckfree(stdMsgPtr);
}
/*
*----------------------------------------------------------------------
*
* Std_MakeChildrenProc --
*
* See ratFolder.h
*
*----------------------------------------------------------------------
*/
void
Std_MakeChildrenProc(Tcl_Interp *interp, BodyInfo *bodyInfoPtr)
{
StdBodyInfo *stdBodyInfoPtr = (StdBodyInfo*)bodyInfoPtr->clientData;
BODY *bodyPtr = bodyInfoPtr->bodyPtr;
BodyInfo *partInfoPtr, **partInfoPtrPtr;
StdBodyInfo *partStdInfoPtr;
int index = 1;
PART *partPtr;
int size;
if (!bodyInfoPtr->firstbornPtr) {
partInfoPtrPtr = &bodyInfoPtr->firstbornPtr;
for (partPtr = bodyPtr->nested.part; partPtr;
partPtr = partPtr->next) {
partInfoPtr = CreateBodyInfo(bodyInfoPtr->msgPtr);
partStdInfoPtr = (StdBodyInfo*)ckalloc(sizeof(StdBodyInfo));
*partInfoPtrPtr = partInfoPtr;
partInfoPtr->bodyPtr = &partPtr->body;
partInfoPtrPtr = &partInfoPtr->nextPtr;
partInfoPtr->msgPtr = bodyInfoPtr->msgPtr;
partInfoPtr->clientData = (ClientData)partStdInfoPtr;
if (stdBodyInfoPtr->section) {
size = strlen(stdBodyInfoPtr->section) + 8;
partStdInfoPtr->section = (char*)ckalloc(size);
snprintf(partStdInfoPtr->section, size, "%s.%d",
stdBodyInfoPtr->section, index++);
} else {
partStdInfoPtr->section = (char*)ckalloc(8);
sprintf(partStdInfoPtr->section, "%d", index++);
}
}
}
}
/*
*----------------------------------------------------------------------
*
* Std_FetchBodyProc --
*
* See ratFolder.h
*
*----------------------------------------------------------------------
*/
char*
Std_FetchBodyProc(BodyInfo *bodyInfoPtr, unsigned long *lengthPtr)
{
StdMessageInfo *stdMsgPtr=(StdMessageInfo*)bodyInfoPtr->msgPtr->clientData;
if (bodyInfoPtr->decodedTextPtr) {
*lengthPtr = Tcl_DStringLength(bodyInfoPtr->decodedTextPtr);
return Tcl_DStringValue(bodyInfoPtr->decodedTextPtr);
}
return mail_fetchbody_full(stdMsgPtr->stream, bodyInfoPtr->msgPtr->msgNo+1,
((StdBodyInfo*)(bodyInfoPtr->clientData))->section, lengthPtr,NIL);
}
/*
*----------------------------------------------------------------------
*
* Std_BodyDeleteProc --
*
* See ratFolder.h
*
*----------------------------------------------------------------------
*/
void
Std_BodyDeleteProc(BodyInfo *bodyInfoPtr)
{
StdBodyInfo *partStdInfoPtr = (StdBodyInfo*)bodyInfoPtr->clientData;
ckfree(partStdInfoPtr->section);
ckfree(bodyInfoPtr->clientData);
}
/*
*----------------------------------------------------------------------
*
* Std_GetInternalDateProc --
*
* See ratFolder.h
*
*----------------------------------------------------------------------
*/
MESSAGECACHE*
Std_GetInternalDateProc(Tcl_Interp *interp, MessageInfo *msgPtr)
{
StdMessageInfo *stdMsgPtr = (StdMessageInfo*)msgPtr->clientData;
return stdMsgPtr->eltPtr;
}
/*
*----------------------------------------------------------------------
*
* Std_GetInfoProc --
*
* See ratFolder.h
*
*----------------------------------------------------------------------
*/
Tcl_Obj*
Std_GetInfoProc(Tcl_Interp *interp, ClientData clientData,
RatFolderInfoType type, int notused)
{
Tcl_Obj *oPtr = NULL;
MessageInfo *msgPtr = (MessageInfo*)clientData;
StdMessageInfo *stdMsgPtr = (StdMessageInfo*)msgPtr->clientData;
ADDRESS *addressPtr;
int i, presIndex;
if (msgPtr->info[type]) {
if (type == RAT_FOLDER_INDEX && msgPtr->folderInfoPtr) {
Tcl_GetIntFromObj(interp, msgPtr->info[type], &i);
if (i < msgPtr->folderInfoPtr->visible
&& msgPtr->folderInfoPtr->privatePtr[
msgPtr->folderInfoPtr->presentationOrder[i-1]] ==
(ClientData)msgPtr) {
return msgPtr->info[type];
}
} else {
return msgPtr->info[type];
}
}
switch (type) {
case RAT_FOLDER_SUBJECT: /* fallthrough */
case RAT_FOLDER_CANONSUBJECT: /* fallthrough */
case RAT_FOLDER_NAME: /* fallthrough */
case RAT_FOLDER_MAIL_REAL: /* fallthrough */
case RAT_FOLDER_MAIL: /* fallthrough */
case RAT_FOLDER_NAME_RECIPIENT: /* fallthrough */
case RAT_FOLDER_MAIL_RECIPIENT: /* fallthrough */
case RAT_FOLDER_SIZE: /* fallthrough */
case RAT_FOLDER_SIZE_F: /* fallthrough */
case RAT_FOLDER_DATE_F: /* fallthrough */
case RAT_FOLDER_DATE_N: /* fallthrough */
case RAT_FOLDER_DATE_IMAP4: /* fallthrough */
case RAT_FOLDER_TO: /* fallthrough */
case RAT_FOLDER_FROM: /* fallthrough */
case RAT_FOLDER_SENDER: /* fallthrough */
case RAT_FOLDER_CC: /* fallthrough */
case RAT_FOLDER_FLAGS: /* fallthrough */
case RAT_FOLDER_UNIXFLAGS: /* fallthrough */
case RAT_FOLDER_MSGID: /* fallthrough */
case RAT_FOLDER_REF: /* fallthrough */
case RAT_FOLDER_THREADING: /* fallthrough */
case RAT_FOLDER_REPLY_TO:
return RatGetMsgInfo(interp, type, msgPtr, stdMsgPtr->envPtr,
NULL, stdMsgPtr->eltPtr, stdMsgPtr->eltPtr->rfc822_size);
case RAT_FOLDER_PARAMETERS:
if (!stdMsgPtr->bodyPtr) {
stdMsgPtr->envPtr = mail_fetchstructure_full(
stdMsgPtr->stream, msgPtr->msgNo+1,
&stdMsgPtr->bodyPtr, NIL);
}
return RatGetMsgInfo(interp, type, msgPtr, stdMsgPtr->envPtr,
stdMsgPtr->bodyPtr, stdMsgPtr->eltPtr,
stdMsgPtr->eltPtr->rfc822_size);
case RAT_FOLDER_TYPE:
if (stdMsgPtr->envPtr->optional.subtype) {
oPtr = Tcl_NewStringObj(
body_types[stdMsgPtr->envPtr->optional.type], -1);
Tcl_AppendStringsToObj(oPtr, "/",
stdMsgPtr->envPtr->optional.subtype,
NULL);
} else {
if (!stdMsgPtr->bodyPtr) {
stdMsgPtr->envPtr = mail_fetchstructure_full(
stdMsgPtr->stream, msgPtr->msgNo+1,
&stdMsgPtr->bodyPtr, NIL);
}
oPtr=Tcl_NewStringObj(body_types[stdMsgPtr->bodyPtr->type],-1);
Tcl_AppendStringsToObj(oPtr, "/",
stdMsgPtr->bodyPtr->subtype, NULL);
}
break;
case RAT_FOLDER_STATUS:
if (RAT_ISME_UNKOWN == msgPtr->toMe) {
msgPtr->toMe = RAT_ISME_NO;
for (addressPtr = stdMsgPtr->envPtr->to; addressPtr;
addressPtr = addressPtr->next) {
if (RatAddressIsMe(interp, addressPtr, 1)) {
msgPtr->toMe = RAT_ISME_YES;
break;
}
}
}
oPtr = Tcl_NewStringObj(NULL, 0);
if (!stdMsgPtr->eltPtr->seen) {
Tcl_AppendToObj(oPtr, "N", 1);
}
if (stdMsgPtr->eltPtr->deleted) {
Tcl_AppendToObj(oPtr, "D", 1);
}
if (stdMsgPtr->eltPtr->flagged) {
Tcl_AppendToObj(oPtr, "F", 1);
}
if (stdMsgPtr->eltPtr->answered) {
Tcl_AppendToObj(oPtr, "A", 1);
}
if (RAT_ISME_YES == msgPtr->toMe) {
Tcl_AppendToObj(oPtr, "+", 1);
} else {
Tcl_AppendToObj(oPtr, " ", 1);
}
break;
case RAT_FOLDER_INDEX:
if (msgPtr->folderInfoPtr) {
for (i=0; i< msgPtr->folderInfoPtr->number; i++) {
presIndex = msgPtr->folderInfoPtr->presentationOrder[i];
if (msgPtr->folderInfoPtr->privatePtr[presIndex] ==
(ClientData)msgPtr){
oPtr = Tcl_NewIntObj(i+1);
break;
}
}
}
break;
case RAT_FOLDER_END:
break;
}
if (!oPtr) {
oPtr = Tcl_NewObj();
}
msgPtr->info[type] = oPtr;
Tcl_IncrRefCount(oPtr);
return oPtr;
}
/*
*----------------------------------------------------------------------
*
* RatStdMsgStructInit --
*
* Initializes the client data part of the message info structures
*
* Results:
* None.
*
* Side effects:
* More data is allocated
*
*
*----------------------------------------------------------------------
*/
void
RatStdMsgStructInit(RatFolderInfoPtr infoPtr, Tcl_Interp *interp, int index,
MAILSTREAM *stream, RatStdFolderType type)
{
StdMessageInfo *stdMsgPtr;
int i, start, end;
char seq[32];
if (-1 == index) {
start = 0;
end = infoPtr->number;
sprintf(seq, "%d:%d", 1, end);
} else {
start = index;
end = start+1;
sprintf(seq, "%d", end);
}
for (i=start; i<end; i++) {
stdMsgPtr = (StdMessageInfo*)ckalloc(sizeof(StdMessageInfo));
stdMsgPtr->stream = stream;
stdMsgPtr->eltPtr = mail_elt(stream, i+1);
stdMsgPtr->envPtr = mail_fetch_structure(stream, i+1, NIL, NIL);
stdMsgPtr->bodyPtr = NULL;
stdMsgPtr->type = type;
stdMsgPtr->spec = NULL;
((MessageInfo*)infoPtr->privatePtr[i])->clientData =
(ClientData)stdMsgPtr;
}
}
#ifdef MEM_DEBUG
void ratStdMessageCleanup()
{
ckfree(mem_header);
}
#endif /* MEM_DEBUG */
syntax highlighted by Code2HTML, v. 0.9.1