/* * 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; istream = 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 */