avoid decoding mime-parts unless we realy need to.
[citadel.git] / citadel / msgbase.c
index a34530828c423528d04865b171f20919dfba587d..41b8171b9fb289f34697063d02dae06f9a2a5da9 100644 (file)
@@ -1427,16 +1427,27 @@ void choose_preferred(char *name, char *filename, char *partnum, char *disp,
 /*
  * Now that we've chosen our preferred part, output it.
  */
-void output_preferred(char *name, char *filename, char *partnum, char *disp,
-               void *content, char *cbtype, char *cbcharset, size_t length,
-               char *encoding, char *cbid, void *cbuserdata)
+void output_preferred(char *name, 
+                     char *filename, 
+                     char *partnum, 
+                     char *disp,
+                     void *content, 
+                     char *cbtype, 
+                     char *cbcharset, 
+                     size_t length,
+                     char *encoding, 
+                     char *cbid, 
+                     void *cbuserdata)
 {
        int i;
        char buf[128];
        int add_newline = 0;
        char *text_content;
        struct ma_info *ma;
-       
+       char *decoded = NULL;
+       size_t bytes_decoded;
+       int rc = 0;
+
        ma = (struct ma_info *)cbuserdata;
 
        /* This is not the MIME part you're looking for... */
@@ -1449,8 +1460,21 @@ void output_preferred(char *name, char *filename, char *partnum, char *disp,
                extract_token(buf, CC->preferred_formats, i, '|', sizeof buf);
                if (!strcasecmp(buf, cbtype)) {
                        /* Yeah!  Go!  W00t!! */
+                       if (ma->dont_decode == 0)
+                               rc = mime_decode_now (content, 
+                                                     length,
+                                                     encoding,
+                                                     &decoded,
+                                                     &bytes_decoded);
+                       if (rc < 0)
+                               break; /* Give us the chance, maybe theres another one. */
+
+                       if (rc == 0) text_content = (char *)content;
+                       else {
+                               text_content = decoded;
+                               length = bytes_decoded;
+                       }
 
-                       text_content = (char *)content;
                        if (text_content[length-1] != '\n') {
                                ++add_newline;
                        }
@@ -1470,14 +1494,32 @@ void output_preferred(char *name, char *filename, char *partnum, char *disp,
                        cprintf("\n");
                        client_write(content, length);
                        if (add_newline) cprintf("\n");
+                       if (decoded != NULL) free(decoded);
                        return;
                }
        }
 
        /* No translations required or possible: output as text/plain */
        cprintf("Content-type: text/plain\n\n");
-       fixed_output(name, filename, partnum, disp, content, cbtype, cbcharset,
+       rc = 0;
+       if (ma->dont_decode == 0)
+               rc = mime_decode_now (content, 
+                                     length,
+                                     encoding,
+                                     &decoded,
+                                     &bytes_decoded);
+       if (rc < 0)
+               return; /* Give us the chance, maybe theres another one. */
+       
+       if (rc == 0) text_content = (char *)content;
+       else {
+               text_content = decoded;
+               length = bytes_decoded;
+       }
+
+       fixed_output(name, filename, partnum, disp, text_content, cbtype, cbcharset,
                        length, encoding, cbid, cbuserdata);
+       if (decoded != NULL) free(decoded);
 }
 
 
@@ -2292,7 +2334,7 @@ START_TEXT:
                                (do_proto ? *list_this_part : NULL),
                                (do_proto ? *list_this_pref : NULL),
                                (do_proto ? *list_this_suff : NULL),
-                               (void *)&ma, 0);
+                               (void *)&ma, 1);
                }
                else if (mode == MT_RFC822) {   /* unparsed RFC822 dump */
                        Dump_RFC822HeadersBody(
@@ -2347,11 +2389,12 @@ START_TEXT:
                        ma.use_fo_hooks = 0;
                        strcpy(ma.chosen_part, "1");
                        ma.chosen_pref = 9999;
+                       ma.dont_decode = CC->msg4_dont_decode;
                        mime_parser(mptr, NULL,
                                *choose_preferred, *fixed_output_pre,
-                               *fixed_output_post, (void *)&ma, 0);
+                               *fixed_output_post, (void *)&ma, 1);
                        mime_parser(mptr, NULL,
-                               *output_preferred, NULL, NULL, (void *)&ma, CC->msg4_dont_decode);
+                               *output_preferred, NULL, NULL, (void *)&ma, 1);
                }
                else {
                        ma.use_fo_hooks = 1;
@@ -3398,7 +3441,7 @@ StrBuf *CtdlReadMessageBodyBuf(char *terminator,  /* token signalling EOT */
        /* read in the lines of message text one by one */
        do {
                if (sock != NULL) {
-                       if ((CtdlSockGetLine(sock, LineBuf) < 0) ||
+                       if ((CtdlSockGetLine(sock, LineBuf, 5) < 0) ||
                            (*sock == -1))
                                finished = 1;
                }
@@ -3489,6 +3532,8 @@ struct CtdlMessage *CtdlMakeMessage(
        char dest_node[256];
        char buf[1024];
        struct CtdlMessage *msg;
+       StrBuf *FakeAuthor;
+       StrBuf *FakeEncAuthor = NULL;
 
        msg = malloc(sizeof(struct CtdlMessage));
        memset(msg, 0, sizeof(struct CtdlMessage));
@@ -3518,11 +3563,14 @@ struct CtdlMessage *CtdlMakeMessage(
        msg->cm_fields['T'] = strdup(buf);
 
        if ((fake_name != NULL) && (fake_name[0])) {            /* author */
-               msg->cm_fields['A'] = strdup(fake_name);
+               FakeAuthor = NewStrBufPlain (fake_name, -1);
        }
        else {
-               msg->cm_fields['A'] = strdup(author->fullname);
+               FakeAuthor = NewStrBufPlain (author->fullname, -1);
        }
+       StrBufRFC2047encode(&FakeEncAuthor, FakeAuthor);
+       msg->cm_fields['A'] = SmashStrBuf(&FakeEncAuthor);
+       FreeStrBuf(&FakeAuthor);
 
        if (CC->room.QRflags & QR_MAILBOX) {            /* room */
                msg->cm_fields['O'] = strdup(&CC->room.QRname[11]);
@@ -3599,10 +3647,13 @@ struct CtdlMessage *CtdlMakeMessage(
  * room.  Returns a *CITADEL ERROR CODE* and puts a message in errmsgbuf, or
  * returns 0 on success.
  */
-int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, 
-                                         size_t n, 
-                                         const char* RemoteIdentifier,
-                                         int PostPublic) {
+int CtdlDoIHavePermissionToPostInThisRoom(
+       char *errmsgbuf, 
+       size_t n, 
+       const char* RemoteIdentifier,
+       int PostPublic,
+       int is_reply
+) {
        int ra;
 
        if (!(CC->logged_in) && 
@@ -3667,7 +3718,18 @@ int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf,
        }
 
        CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL);
-       if (!(ra & UA_POSTALLOWED)) {
+
+       if ( (!(ra & UA_POSTALLOWED)) && (ra & UA_REPLYALLOWED) && (!is_reply) ) {
+               /*
+                * To be thorough, we ought to check to see if the message they are
+                * replying to is actually a valid one in this room, but unless this
+                * actually becomes a problem we'll go with high performance instead.
+                */
+               snprintf(errmsgbuf, n, "You may only reply to existing messages here.");
+               return (ERROR + HIGHER_ACCESS_REQUIRED);
+       }
+
+       else if (!(ra & UA_POSTALLOWED)) {
                snprintf(errmsgbuf, n, "Higher access is required to post in this room.");
                return (ERROR + HIGHER_ACCESS_REQUIRED);
        }
@@ -3827,10 +3889,12 @@ struct recptypes *validate_recipients(const char *supplied_recipients,
                                        CC->room = tempQR;
                                        
                                        /* Check permissions to send mail to this room */
-                                       err = CtdlDoIHavePermissionToPostInThisRoom(errmsg, 
-                                                                                   sizeof errmsg, 
-                                                                                   RemoteIdentifier,
-                                                                                   Flags
+                                       err = CtdlDoIHavePermissionToPostInThisRoom(
+                                               errmsg, 
+                                               sizeof errmsg, 
+                                               RemoteIdentifier,
+                                               Flags,
+                                               0                       /* 0 = not a reply */
                                        );
                                        if (err)
                                        {
@@ -4033,7 +4097,13 @@ void cmd_ent0(char *entargs)
 
        /* first check to make sure the request is valid. */
 
-       err = CtdlDoIHavePermissionToPostInThisRoom(errmsg, sizeof errmsg, NULL, POST_LOGGED_IN);
+       err = CtdlDoIHavePermissionToPostInThisRoom(
+               errmsg,
+               sizeof errmsg,
+               NULL,
+               POST_LOGGED_IN,
+               (!IsEmptyStr(references))               /* is this a reply?  or a top-level post? */
+       );
        if (err)
        {
                cprintf("%d %s\n", err, errmsg);