Rewrote mimepart() as view_or_download_mimepart()
[citadel.git] / webcit / messages.c
index 732ef03b8093686eecdac97baf7a9d3a21b60a9e..7307d5eb6dc91d9953b7765d65df78e1043e6859 100644 (file)
@@ -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.
@@ -488,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;
@@ -521,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");
@@ -543,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.
@@ -568,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;
                                }                                       
@@ -658,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;
 
 
@@ -739,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) {
@@ -899,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("<html><body>\r\n");
-               text_to_server_qp(sbstr("msgtext"));    /* Transmit message in quoted-printable encoding */
-               serv_puts("</body></html>\r\n");
-       }
+       serv_puts("Content-type: text/html; charset=utf-8");
+       serv_puts("Content-Transfer-Encoding: quoted-printable");
+       serv_puts("");
+       serv_puts("<html><body>\r\n");
+       text_to_server_qp(sbstr("msgtext"));    /* Transmit message in quoted-printable encoding */
+       serv_puts("</body></html>\r\n");
 
        if (include_text_alt) {
                serv_printf("--%s--", alt_boundary);
@@ -1002,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;
@@ -1057,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");
                
@@ -1065,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);
@@ -1077,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);
@@ -1331,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"));
        }
@@ -1537,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;
 
                                        }
@@ -1627,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, 
@@ -1643,7 +1668,7 @@ void display_enter(void)
                                        StrLength(display_name) +
                                        StrLength(Cc) +
                                        StrLength(Bcc) + 
-                                       strlen(wikipage));
+                                       StrLength(wikipage));
 
                StrBufPrintf(CmdBuf, 
                             CMD,
@@ -1652,7 +1677,7 @@ void display_enter(void)
                             ChrPtr(display_name),
                             ChrPtr(Cc), 
                             ChrPtr(Bcc), 
-                            wikipage
+                            ChrPtr(wikipage)
                );
                serv_puts(ChrPtr(CmdBuf));
                StrBuf_ServGetln(CmdBuf);
@@ -1681,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;
@@ -1786,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;
-
-       att = Buf = NewStrBuf();
-       msgnum = StrBufExtract_long(WCC->Hdr->HR.ReqLine, 0, '/');
-       StrBufExtract_token(att, WCC->Hdr->HR.ReqLine, 1, '/');
+       StrBuf *Buf;
+       StrBuf *ContentType;
+       StrBuf *PartNum;
 
-       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);
+       PartNum = NewStrBuf();
 
-               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);
 }
 
 
@@ -1906,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();
@@ -1918,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) {
@@ -1992,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,
@@ -2000,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));
@@ -2016,7 +2019,30 @@ 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;
+       }
+
+       Put(ReadLoopHandler, IKEY(RoomType), Handler, FreeReadLoopHandlerSet);
 }
 
 void 
@@ -2042,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);