X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fmessages.c;h=7307d5eb6dc91d9953b7765d65df78e1043e6859;hb=ed4e4918cc03352a056f097ea9e8d24918c49158;hp=a5447a378952ca84674ecaaf01f368fc277653e6;hpb=7c339ad1ffcbbd5b5d0d3610b734405e571d286e;p=citadel.git diff --git a/webcit/messages.c b/webcit/messages.c index a5447a378..7307d5eb6 100644 --- a/webcit/messages.c +++ b/webcit/messages.c @@ -1,7 +1,7 @@ /* * Functions which deal with the fetching and displaying of messages. * - * Copyright (c) 1996-2012 by the citadel.org team + * Copyright (c) 1996-2018 by the citadel.org team * * This program is open source software. You can redistribute it and/or * modify it under the terms of the GNU General Public License, version 3. @@ -17,7 +17,6 @@ #include "dav.h" #include "calendar.h" -HashList *MsgHeaderHandler = NULL; HashList *MimeRenderHandler = NULL; HashList *ReadLoopHandler = NULL; int dbg_analyze_msg = 0; @@ -45,12 +44,11 @@ int load_message(message_summary *Msg, { StrBuf *Buf; StrBuf *HdrToken; - headereval *Hdr; - void *vHdr; char buf[SIZ]; int Done = 0; int state=0; - + int rc; + Buf = NewStrBuf(); if (Msg->PartNum != NULL) { serv_printf("MSG4 %ld|%s", Msg->msgnum, ChrPtr(Msg->PartNum)); @@ -97,14 +95,11 @@ int load_message(message_summary *Msg, StrBufCutLeft(Buf, StrLength(HdrToken) + 1); /* look up one of the examine_* functions to parse the content */ - if (GetHash(MsgHeaderHandler, SKEY(HdrToken), &vHdr) && - (vHdr != NULL)) { - Hdr = (headereval*)vHdr; - Hdr->evaluator(Msg, Buf, FoundCharset); - if (Hdr->Type == 1) { - state++; - } - }/* TODO: + rc = EvaluateMsgHdr(SKEY(HdrToken), Msg, Buf, FoundCharset); + if (rc == 1) { + state++; + } + /* TODO: else LogError(Target, __FUNCTION__, "don't know how to handle message header[%s]\n", @@ -125,11 +120,8 @@ int load_message(message_summary *Msg, if (StrLength(HdrToken) > 0) { StrBufCutLeft(Buf, StrLength(HdrToken) + 1); /* the examine*'s know how to do with mime headers too... */ - if (GetHash(MsgHeaderHandler, SKEY(HdrToken), &vHdr) && - (vHdr != NULL)) { - Hdr = (headereval*)vHdr; - Hdr->evaluator(Msg, Buf, FoundCharset); - } + EvaluateMsgHdr(SKEY(HdrToken), Msg, Buf, FoundCharset); + break; } } @@ -496,8 +488,13 @@ void display_headers(void) { */ int load_msg_ptrs(const char *servcmd, const char *filter, + StrBuf *FoundCharset, SharedMessageStatus *Stat, - load_msg_ptrs_detailheaders LH) + void **ViewSpecific, + load_msg_ptrs_detailheaders LH, + StrBuf *FetchMessageList, + eMessageField *MessageFieldList, + long HeaderCount) { wcsession *WCC = WC; message_summary *Msg; @@ -529,6 +526,10 @@ int load_msg_ptrs(const char *servcmd, serv_puts("000"); break; } + else if (FetchMessageList != NULL) { + serv_putbuf(FetchMessageList); + break; + } /* fall back to empty filter in case of we were fooled... */ serv_puts(""); serv_puts("000"); @@ -551,21 +552,30 @@ int load_msg_ptrs(const char *servcmd, Msg->msgnum = StrBufExtractNext_long(Buf, &Ptr, '|'); Msg->date = StrBufExtractNext_long(Buf, &Ptr, '|'); - - if (Stat->nummsgs == 0) { - if (Msg->msgnum < Stat->lowest_found) { - Stat->lowest_found = Msg->msgnum; - } - if (Msg->msgnum > Stat->highest_found) { - Stat->highest_found = Msg->msgnum; + if (MessageFieldList != NULL) { + long i; + for (i = 0; i < HeaderCount; i++) { + StrBufExtract_NextToken(Buf2, Buf, &Ptr, '|'); + if (StrLength(Buf2) > 0) { + EvaluateMsgHdrEnum(MessageFieldList[i], Msg, Buf2, FoundCharset); + } } } + else { + if (Stat->nummsgs == 0) { + if (Msg->msgnum < Stat->lowest_found) { + Stat->lowest_found = Msg->msgnum; + } + if (Msg->msgnum > Stat->highest_found) { + Stat->highest_found = Msg->msgnum; + } + } - if ((Msg->msgnum == 0) && (StrLength(Buf) < 32)) { - free(Msg); - continue; + if ((Msg->msgnum == 0) && (StrLength(Buf) < 32)) { + free(Msg); + continue; + } } - /* * as citserver probably gives us messages in forward date sorting * nummsgs should be the same order as the message date. @@ -576,7 +586,7 @@ int load_msg_ptrs(const char *servcmd, skipit = 1; } if ((!skipit) && (LH != NULL)) { - if (!LH(Buf, &Ptr, Msg, Buf2)){ + if (!LH(Buf, &Ptr, Msg, Buf2, ViewSpecific)){ free(Msg); continue; } @@ -666,6 +676,9 @@ typedef struct _RoomRenderer{ RenderView_or_Tail_func RenderView_or_Tail; View_Cleanup_func ViewCleanup; load_msg_ptrs_detailheaders LHParse; + long HeaderCount; + StrBuf *FetchMessageList; + eMessageField *MessageFieldList; } RoomRenderer; @@ -747,9 +760,21 @@ void readloop(long oper, eCustomRoomRenderer ForceRenderer) } if (!IsEmptyStr(cmd)) { const char *p = NULL; + StrBuf *FoundCharset = NULL; if (!IsEmptyStr(filter)) p = filter; - Stat.nummsgs = load_msg_ptrs(cmd, p, &Stat, ViewMsg->LHParse); + if (ViewMsg->HeaderCount > 0) { + FoundCharset = NewStrBuf(); + } + Stat.nummsgs = load_msg_ptrs(cmd, p, + FoundCharset, + &Stat, + &ViewSpecific, + ViewMsg->LHParse, + ViewMsg->FetchMessageList, + ViewMsg->MessageFieldList, + ViewMsg->HeaderCount); + FreeStrBuf(&FoundCharset); } if (Stat.sortit) { @@ -907,22 +932,12 @@ void post_mime_to_server(void) { serv_printf("\n--%s", alt_boundary); } - if (havebstr("markdown")) - { - serv_puts("Content-type: text/x-markdown; charset=utf-8"); - serv_puts("Content-Transfer-Encoding: quoted-printable"); - serv_puts(""); - text_to_server_qp(sbstr("msgtext")); /* Transmit message in quoted-printable encoding */ - } - else - { - serv_puts("Content-type: text/html; charset=utf-8"); - serv_puts("Content-Transfer-Encoding: quoted-printable"); - serv_puts(""); - serv_puts("\r\n"); - text_to_server_qp(sbstr("msgtext")); /* Transmit message in quoted-printable encoding */ - serv_puts("\r\n"); - } + serv_puts("Content-type: text/html; charset=utf-8"); + serv_puts("Content-Transfer-Encoding: quoted-printable"); + serv_puts(""); + serv_puts("\r\n"); + text_to_server_qp(sbstr("msgtext")); /* Transmit message in quoted-printable encoding */ + serv_puts("\r\n"); if (include_text_alt) { serv_printf("--%s--", alt_boundary); @@ -1010,7 +1025,7 @@ void post_message(void) StrBuf *Recp = NULL; StrBuf *Cc = NULL; StrBuf *Bcc = NULL; - char *wikipage = NULL; + StrBuf *wikipage = NULL; const StrBuf *my_email_addr = NULL; StrBuf *CmdBuf = NULL; StrBuf *references = NULL; @@ -1065,7 +1080,7 @@ void post_message(void) FreeStrBuf(&EmailAddress); FreeStrBuf(&EncBuf); - wikipage = strdup(bstr("page")); + wikipage = NewStrBufDup(sbstr("page")); str_wiki_index(wikipage); my_email_addr = sbstr("my_email_addr"); @@ -1073,7 +1088,7 @@ void post_message(void) StrLength(encoded_subject) + StrLength(Cc) + StrLength(Bcc) + - strlen(wikipage) + + StrLength(wikipage) + StrLength(my_email_addr) + StrLength(references); CmdBuf = NewStrBufPlain(NULL, sizeof (CMD) + HeaderLen); @@ -1085,7 +1100,7 @@ void post_message(void) ChrPtr(display_name), saving_to_drafts?"":ChrPtr(Cc), saving_to_drafts?"":ChrPtr(Bcc), - wikipage, + ChrPtr(wikipage), ChrPtr(my_email_addr), ChrPtr(references)); FreeStrBuf(&references); @@ -1310,77 +1325,6 @@ void remove_attachment(void) { } -/* Maps to msgkeys[] in msgbase.c: */ - -typedef enum _eMessageField { - eAuthor, - eXclusivID, - erFc822Addr, - eHumanNode, - emessageId, - eJournal, - eReplyTo, - eListID, - eMesageText, - eNodeName, - eOriginalRoom, - eMessagePath, - eRecipient, - eSpecialField, - eTimestamp, - eMsgSubject, - eenVelopeTo, - eWeferences, - eCarbonCopY -}eMessageField; - -const char* fieldMnemonics[] = { - "from", /* A -> eAuthor */ - "exti", /* E -> eXclusivID */ - "rfca", /* F -> erFc822Addr */ - "hnod", /* H -> eHumanNode */ - "msgn", /* I -> emessageId */ - "jrnl", /* J -> eJournal */ - "rep2", /* K -> eReplyTo */ - "list", /* L -> eListID */ - "text", /* M -> eMesageText */ - "node", /* N -> eNodeName */ - "room", /* O -> eOriginalRoom */ - "path", /* P -> eMessagePath */ - "rcpt", /* R -> eRecipient */ - "spec", /* S -> eSpecialField */ - "time", /* T -> eTimestamp */ - "subj", /* U -> eMsgSubject */ - "nvto", /* V -> eenVelopeTo */ - "wefw", /* W -> eWeferences */ - "cccc" /* Y -> eCarbonCopY */ -}; - -HashList *msgKeyLookup = NULL; - -int GetFieldFromMnemonic(eMessageField *f, const char* c) -{ - void *v = NULL; - if (GetHash(msgKeyLookup, c, 4, &v)) { - *f = (eMessageField) v; - return 1; - } - return 0; -} - -void FillMsgKeyLookupTable(void) -{ - long i; - - msgKeyLookup = NewHash (1, FourHash); - - for (i=0; i < 20; i++) { - if (fieldMnemonics[i] != NULL) { - Put(msgKeyLookup, fieldMnemonics[i], 4, (void*)i, reference_free_handler); - } - } -} - const char *ReplyToModeStrings [3] = { "reply", "replyall", @@ -1410,10 +1354,6 @@ void display_enter(void) int i = 0; long replying_to; - int prefer_md; - - get_pref_yesno("markdown", &prefer_md, 0); - if (havebstr("force_room")) { gotoroom(sbstr("force_room")); } @@ -1616,6 +1556,12 @@ void display_enter(void) case eMessagePath: case eSpecialField: case eTimestamp: + case eHeaderOnly: + case eFormatType: + case eMessagePart: + case eSubFolder: + case ePevious: + case eLastHeader: break; } @@ -1706,14 +1652,14 @@ void display_enter(void) const StrBuf *Recp = NULL; const StrBuf *Cc = NULL; const StrBuf *Bcc = NULL; - char *wikipage = NULL; + StrBuf *wikipage = NULL; StrBuf *CmdBuf = NULL; const char CMD[] = "ENT0 0|%s|%d|0||%s||%s|%s|%s"; Recp = sbstr("recp"); Cc = sbstr("cc"); Bcc = sbstr("bcc"); - wikipage = strdup(bstr("page")); + wikipage = NewStrBufDup(sbstr("page")); str_wiki_index(wikipage); CmdBuf = NewStrBufPlain(NULL, @@ -1722,7 +1668,7 @@ void display_enter(void) StrLength(display_name) + StrLength(Cc) + StrLength(Bcc) + - strlen(wikipage)); + StrLength(wikipage)); StrBufPrintf(CmdBuf, CMD, @@ -1731,7 +1677,7 @@ void display_enter(void) ChrPtr(display_name), ChrPtr(Cc), ChrPtr(Bcc), - wikipage + ChrPtr(wikipage) ); serv_puts(ChrPtr(CmdBuf)); StrBuf_ServGetln(CmdBuf); @@ -1760,10 +1706,7 @@ void display_enter(void) begin_burst(); output_headers(1, 0, 0, 0, 1, 0); - if ((WCC->CurRoom.defview == VIEW_WIKIMD) || prefer_md) - DoTemplate(HKEY("edit_markdown_epic"), NULL, &NoCtx); - else - DoTemplate(HKEY("edit_message"), NULL, &NoCtx); + DoTemplate(HKEY("edit_message"), NULL, &NoCtx); end_burst(); return; @@ -1865,90 +1808,60 @@ void postpart(StrBuf *partnum, StrBuf *filename, int force_download) * Generic function to output an arbitrary MIME part from an arbitrary * message number on the server. * - * msgnum Number of the item on the citadel server - * partnum The MIME part to be output + * msgnum message number on the citadel server + * partnum MIME part number to be output * force_download Nonzero to force set the Content-Type: header to "application/octet-stream" */ -void mimepart(int force_download) +void view_or_download_mimepart(int force_download) { - int detect_mime = 0; long msgnum; - long ErrorDetail; - StrBuf *att; - wcsession *WCC = WC; - StrBuf *Buf; off_t bytes; - StrBuf *ContentType = NewStrBufPlain(HKEY("application/octet-stream")); - const char *CT; + StrBuf *Buf; + StrBuf *ContentType; + StrBuf *PartNum; - att = Buf = NewStrBuf(); - msgnum = StrBufExtract_long(WCC->Hdr->HR.ReqLine, 0, '/'); - StrBufExtract_token(att, WCC->Hdr->HR.ReqLine, 1, '/'); + PartNum = NewStrBuf(); - serv_printf("OPNA %ld|%s", msgnum, ChrPtr(att)); - StrBuf_ServGetln(Buf); - if (GetServerStatus(Buf, &ErrorDetail) == 2) { - StrBufCutLeft(Buf, 4); - bytes = StrBufExtract_long(Buf, 0, '|'); - StrBufExtract_token(ContentType, Buf, 3, '|'); - CheckGZipCompressionAllowed (SKEY(ContentType)); - if (force_download) - { - FlushStrBuf(ContentType); - detect_mime = 0; - } - else - { - if (!strcasecmp(ChrPtr(ContentType), "application/octet-stream")) - { - StrBufExtract_token(Buf, WCC->Hdr->HR.ReqLine, 2, '/'); - CT = GuessMimeByFilename(SKEY(Buf)); - StrBufPlain(ContentType, CT, -1); - } - if (!strcasecmp(ChrPtr(ContentType), "application/octet-stream")) - { - detect_mime = 1; - } - } - serv_read_binary_to_http(ContentType, bytes, 0, detect_mime); - - serv_read_binary(WCC->WBuf, bytes, Buf); - serv_puts("CLOS"); - StrBuf_ServGetln(Buf); - CT = ChrPtr(ContentType); - } else { - StrBufCutLeft(Buf, 4); - switch (ErrorDetail) { - default: - case ERROR + MESSAGE_NOT_FOUND: - hprintf("HTTP/1.1 404 %s\n", ChrPtr(Buf)); - break; - case ERROR + NOT_LOGGED_IN: - hprintf("HTTP/1.1 401 %s\n", ChrPtr(Buf)); - break; + msgnum = StrBufExtract_long(WC->Hdr->HR.ReqLine, 0, '/'); + StrBufExtract_token(PartNum, WC->Hdr->HR.ReqLine, 1, '/'); - case ERROR + HIGHER_ACCESS_REQUIRED: - hprintf("HTTP/1.1 403 %s\n", ChrPtr(Buf)); - break; - case ERROR + INTERNAL_ERROR: - case ERROR + TOO_BIG: - hprintf("HTTP/1.1 500 %s\n", ChrPtr(Buf)); - break; - } + Buf = NewStrBuf(); + serv_printf("DLAT %ld|%s", msgnum, ChrPtr(PartNum)); // DLAT will return: 6XX length|-1|filename|cbtype|cbcharset + StrBuf_ServGetln(Buf); + FreeStrBuf(&PartNum); - hprintf("Pragma: no-cache\r\n" + if (GetServerStatus(Buf, NULL) != 6) { + FreeStrBuf(&Buf); + hprintf("HTTP/1.1 500 error\r\n" + "Pragma: no-cache\r\n" "Cache-Control: no-store\r\n" "Expires: -1\r\n" + "Content-Type: text/plain\r\n" ); - - hprintf("Content-Type: text/plain\r\n"); begin_burst(); - wc_printf(_("An error occurred while retrieving this part: %s\n"), - ChrPtr(Buf)); - end_burst(); + wc_printf(_("An error occurred while retrieving this part: %s\n"), "--"); + return; } - FreeStrBuf(&ContentType); + + StrBufCutLeft(Buf, 4); + bytes = StrBufExtract_long(Buf, 0, '|'); + + if (force_download) { + ContentType = NewStrBufPlain(HKEY("application/octet-stream")); + } + else { + ContentType = NewStrBuf(); + StrBufExtract_token(ContentType, Buf, 3, '|'); + } + FreeStrBuf(&Buf); + Buf = NewStrBuf(); + StrBuf_ServGetBLOBBuffered(Buf, bytes); + + WC->WBuf = Buf; + Buf = NULL; + http_transmit_thing(ChrPtr(ContentType), 0); + FreeStrBuf(&ContentType); } @@ -1985,7 +1898,6 @@ void MimeLoadData(wc_mime_attachment *Mime) StrBuf *Buf; const char *Ptr; off_t bytes; - /* TODO: is there a chance the content type is different from the one we know? */ serv_printf("DLAT %ld|%s", Mime->msgnum, ChrPtr(Mime->PartNum)); Buf = NewStrBuf(); @@ -1997,24 +1909,24 @@ void MimeLoadData(wc_mime_attachment *Mime) if (Mime->Charset == NULL) Mime->Charset = NewStrBuf(); StrBufExtract_NextToken(Mime->Charset, Buf, &Ptr, '|'); - if (Mime->Data == NULL) + if (Mime->Data == NULL) { Mime->Data = NewStrBufPlain(NULL, bytes); + } StrBuf_ServGetBLOBBuffered(Mime->Data, bytes); } else { FlushStrBuf(Mime->Data); - /* TODO XImportant message */ } FreeStrBuf(&Buf); } void view_mimepart(void) { - mimepart(0); + view_or_download_mimepart(0); } void download_mimepart(void) { - mimepart(1); + view_or_download_mimepart(1); } void view_postpart(void) { @@ -2071,6 +1983,15 @@ void jsonMessageList(void) { readloop(oper, eUseDefault); } +void FreeReadLoopHandlerSet(void *v) { + RoomRenderer *Handler = (RoomRenderer *) v; + FreeStrBuf(&Handler->FetchMessageList); + if (Handler->MessageFieldList != NULL) { + free(Handler->MessageFieldList); + } + free(Handler); +} + void RegisterReadLoopHandlerset( int RoomType, GetParamsGetServerCall_func GetParamsGetServerCall, @@ -2079,9 +2000,12 @@ void RegisterReadLoopHandlerset( load_msg_ptrs_detailheaders LH, LoadMsgFromServer_func LoadMsgFromServer, RenderView_or_Tail_func RenderView_or_Tail, - View_Cleanup_func ViewCleanup + View_Cleanup_func ViewCleanup, + const char **browseListFields ) { + long count = 0; + long i = 0; RoomRenderer *Handler; Handler = (RoomRenderer*) malloc(sizeof(RoomRenderer)); @@ -2095,28 +2019,42 @@ void RegisterReadLoopHandlerset( Handler->ViewCleanup = ViewCleanup; Handler->LHParse = LH; - Put(ReadLoopHandler, IKEY(RoomType), Handler, NULL); -} + if (browseListFields != NULL) { + while (browseListFields[count] != NULL) { + count ++; + } + Handler->HeaderCount = count; + Handler->MessageFieldList = (eMessageField*) malloc(sizeof(eMessageField) * count); + Handler->FetchMessageList = NewStrBufPlain(NULL, 5 * count + 4 + 5); + StrBufPlain(Handler->FetchMessageList, HKEY("time\n")); + for (i = 0; i < count; i++) { + if (!GetFieldFromMnemonic(&Handler->MessageFieldList[i], browseListFields[i])) { + fprintf(stderr, "Unknown message header: %s\n", browseListFields[i]); + exit(1); + } + StrBufAppendBufPlain(Handler->FetchMessageList, browseListFields[i], 4, 0); + StrBufAppendBufPlain(Handler->FetchMessageList, HKEY("\n"), 0); + } + StrBufAppendBufPlain(Handler->FetchMessageList, HKEY("000"), 0); + } + else { + Handler->FetchMessageList = NULL; + Handler->MessageFieldList = NULL; + } -void -ServerShutdownModule_MSG -(void) -{ - DeleteHash(&msgKeyLookup); + Put(ReadLoopHandler, IKEY(RoomType), Handler, FreeReadLoopHandlerSet); } void InitModule_MSG (void) { - FillMsgKeyLookupTable(); - RegisterPreference("use_sig", _("Attach signature to email messages?"), PRF_YESNO, NULL); RegisterPreference("signature", _("Use this signature:"), PRF_QP_STRING, NULL); - RegisterPreference("default_header_charset", + RegisterPreference("default_header_charset", _("Default character set for email headers:"), PRF_STRING, NULL); @@ -2130,8 +2068,6 @@ InitModule_MSG PRF_STRING, NULL); RegisterPreference("mailbox",_("Mailbox view mode"), PRF_STRING, NULL); - RegisterPreference("markdown",_("Prefer markdown editing"), PRF_YESNO, NULL); - WebcitAddUrlHandler(HKEY("readnew"), "", 0, h_readnew, ANONYMOUS|NEED_URL); WebcitAddUrlHandler(HKEY("readold"), "", 0, h_readold, ANONYMOUS|NEED_URL);