Moved all threading code into threads.c
[citadel.git] / citadel / msgbase.c
index 37cd9c6ccc9f08a3278f2646cf5ac1d81dd988d6..6fc437faf5ace9b3ad333b3fc70b73d0b5ef18c6 100644 (file)
@@ -31,6 +31,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <regex.h>
+#include <libcitadel.h>
 #include "citadel.h"
 #include "server.h"
 #include "serv_extensions.h"
 #include "file_ops.h"
 #include "config.h"
 #include "control.h"
-#include "tools.h"
-#include "mime_parser.h"
 #include "html.h"
 #include "genstamp.h"
 #include "internet_addressing.h"
-#include "vcard.h"
 #include "euidindex.h"
 #include "journaling.h"
 #include "citadel_dirs.h"
 #include "clientsocket.h"
-
+#include "serv_network.h"
+#include "threads.h"
 
 long config_msgnum;
 struct addresses_to_be_filed *atbf = NULL;
@@ -1264,15 +1263,14 @@ void choose_preferred(char *name, char *filename, char *partnum, char *disp,
        //       http://bugzilla.citadel.org/show_bug.cgi?id=220
        // I don't know if there are any side effects!  Please TEST TEST TEST
        //if (ma->is_ma > 0) {
-       if (1) {
-               for (i=0; i<num_tokens(CC->preferred_formats, '|'); ++i) {
-                       extract_token(buf, CC->preferred_formats, i, '|', sizeof buf);
-                       if ( (!strcasecmp(buf, cbtype)) && (!ma->freeze) ) {
-                               if (i < ma->chosen_pref) {
-                                       lprintf(CTDL_DEBUG, "Setting chosen part: <%s>\n", partnum);
-                                       safestrncpy(ma->chosen_part, partnum, sizeof ma->chosen_part);
-                                       ma->chosen_pref = i;
-                               }
+
+       for (i=0; i<num_tokens(CC->preferred_formats, '|'); ++i) {
+               extract_token(buf, CC->preferred_formats, i, '|', sizeof buf);
+               if ( (!strcasecmp(buf, cbtype)) && (!ma->freeze) ) {
+                       if (i < ma->chosen_pref) {
+                               lprintf(CTDL_DEBUG, "Setting chosen part: <%s>\n", partnum);
+                               safestrncpy(ma->chosen_part, partnum, sizeof ma->chosen_part);
+                               ma->chosen_pref = i;
                        }
                }
        }
@@ -1812,21 +1810,26 @@ START_TEXT:
         * what message transfer format is in use.
         */
        if (TheMessage->cm_format_type == FMT_FIXED) {
+               int buflen;
                if (mode == MT_MIME) {
                        cprintf("Content-type: text/plain\n\n");
                }
-               strcpy(buf, "");
+               *buf = '\0';
+               buflen = 0;
                while (ch = *mptr++, ch > 0) {
                        if (ch == 13)
                                ch = 10;
-                       if ((ch == 10) || (strlen(buf) > 250)) {
+                       if ((ch == 10) || (buflen > 250)) {
+                               buf[buflen] = '\0';
                                cprintf("%s%s", buf, nl);
-                               strcpy(buf, "");
+                               *buf = '\0';
+                               buflen = 0;
                        } else {
-                               buf[strlen(buf) + 1] = 0;
-                               buf[strlen(buf)] = ch;
+                               buf[buflen] = ch;
+                               buflen++;
                        }
                }
+               buf[buflen] = '\0';
                if (!IsEmptyStr(buf))
                        cprintf("%s%s", buf, nl);
        }
@@ -1861,7 +1864,7 @@ START_TEXT:
                                *choose_preferred, *fixed_output_pre,
                                *fixed_output_post, (void *)&ma, 0);
                        mime_parser(mptr, NULL,
-                               *output_preferred, NULL, NULL, (void *)&ma, 0);
+                               *output_preferred, NULL, NULL, (void *)&ma, CC->msg4_dont_decode);
                }
                else {
                        ma.use_fo_hooks = 1;
@@ -1970,9 +1973,14 @@ void cmd_msg4(char *cmdbuf)
  */
 void cmd_msgp(char *cmdbuf)
 {
-       safestrncpy(CC->preferred_formats, cmdbuf,
-                       sizeof(CC->preferred_formats));
-       cprintf("%d ok\n", CIT_OK);
+       if (!strcasecmp(cmdbuf, "dont_decode")) {
+               CC->msg4_dont_decode = 1;
+               cprintf("%d MSG4 will not pre-decode messages.\n", CIT_OK);
+       }
+       else {
+               safestrncpy(CC->preferred_formats, cmdbuf, sizeof(CC->preferred_formats));
+               cprintf("%d Preferred MIME formats have been set.\n", CIT_OK);
+       }
 }
 
 
@@ -2316,6 +2324,43 @@ void serialize_message(struct ser_ret *ret,              /* return values */
 }
 
 
+/*
+ * Serialize a struct CtdlMessage into the format used on disk and network.
+ * 
+ * This function loads up a "struct ser_ret" (defined in server.h) which
+ * contains the length of the serialized message and a pointer to the
+ * serialized message in memory.  THE LATTER MUST BE FREED BY THE CALLER.
+ */
+void dump_message(struct CtdlMessage *msg,     /* unserialized msg */
+                 long Siz)                     /* how many chars ? */
+{
+       size_t wlen;
+       int i;
+       static char *forder = FORDER;
+       char *buf;
+
+       /*
+        * Check for valid message format
+        */
+       if (is_valid_message(msg) == 0) {
+               lprintf(CTDL_ERR, "dump_message() aborting due to invalid message\n");
+               return;
+       }
+
+       buf = (char*) malloc (Siz + 1);
+
+       wlen = 3;
+       
+       for (i=0; i<26; ++i) if (msg->cm_fields[(int)forder[i]] != NULL) {
+                       snprintf (buf, Siz, " msg[%c] = %s ...\n", (char) forder[i], 
+                                  msg->cm_fields[(int)forder[i]]);
+                       client_write (buf, strlen(buf));
+               }
+
+       return;
+}
+
+
 
 /*
  * Check to see if any messages already exist in the current room which
@@ -2375,6 +2420,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
        struct addresses_to_be_filed *aptr = NULL;
        char *saved_rfc822_version = NULL;
        int qualified_for_journaling = 0;
+       struct CitContext *CCC = CC;            /* CachedCitContext - performance boost */
 
        lprintf(CTDL_DEBUG, "CtdlSubmitMsg() called\n");
        if (is_valid_message(msg) == 0) return(-1);     /* self check */
@@ -2441,16 +2487,16 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,     /* message to save */
        }
 
        /* Goto the correct room */
-       lprintf(CTDL_DEBUG, "Selected room %s\n", (recps) ? CC->room.QRname : SENTITEMS);
-       strcpy(hold_rm, CC->room.QRname);
-       strcpy(actual_rm, CC->room.QRname);
+       lprintf(CTDL_DEBUG, "Selected room %s\n", (recps) ? CCC->room.QRname : SENTITEMS);
+       strcpy(hold_rm, CCC->room.QRname);
+       strcpy(actual_rm, CCC->room.QRname);
        if (recps != NULL) {
                strcpy(actual_rm, SENTITEMS);
        }
 
        /* If the user is a twit, move to the twit room for posting */
        if (TWITDETECT) {
-               if (CC->user.axlevel == 2) {
+               if (CCC->user.axlevel == 2) {
                        strcpy(hold_rm, actual_rm);
                        strcpy(actual_rm, config.c_twitroom);
                        lprintf(CTDL_DEBUG, "Diverting to twit room\n");
@@ -2463,8 +2509,8 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
        }
 
        lprintf(CTDL_DEBUG, "Final selection: %s\n", actual_rm);
-       if (strcasecmp(actual_rm, CC->room.QRname)) {
-               /* getroom(&CC->room, actual_rm); */
+       if (strcasecmp(actual_rm, CCC->room.QRname)) {
+               /* getroom(&CCC->room, actual_rm); */
                usergoto(actual_rm, 0, 1, NULL, NULL);
        }
 
@@ -2472,7 +2518,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
         * If this message has no O (room) field, generate one.
         */
        if (msg->cm_fields['O'] == NULL) {
-               msg->cm_fields['O'] = strdup(CC->room.QRname);
+               msg->cm_fields['O'] = strdup(CCC->room.QRname);
        }
 
        /* Perform "before save" hooks (aborting if any return nonzero) */
@@ -2483,7 +2529,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
         * If this message has an Exclusive ID, and the room is replication
         * checking enabled, then do replication checks.
         */
-       if (DoesThisRoomNeedEuidIndexing(&CC->room)) {
+       if (DoesThisRoomNeedEuidIndexing(&CCC->room)) {
                ReplicationChecks(msg);
        }
 
@@ -2513,19 +2559,19 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,     /* message to save */
         * 2. If journaling is enabled, we will need an RFC822 version of the
         *    message to attach to the journalized copy.
         */
-       if (CC->redirect_buffer != NULL) {
-               lprintf(CTDL_ALERT, "CC->redirect_buffer is not NULL during message submission!\n");
+       if (CCC->redirect_buffer != NULL) {
+               lprintf(CTDL_ALERT, "CCC->redirect_buffer is not NULL during message submission!\n");
                abort();
        }
-       CC->redirect_buffer = malloc(SIZ);
-       CC->redirect_len = 0;
-       CC->redirect_alloc = SIZ;
+       CCC->redirect_buffer = malloc(SIZ);
+       CCC->redirect_len = 0;
+       CCC->redirect_alloc = SIZ;
        CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1);
-       smi.meta_rfc822_length = CC->redirect_len;
-       saved_rfc822_version = CC->redirect_buffer;
-       CC->redirect_buffer = NULL;
-       CC->redirect_len = 0;
-       CC->redirect_alloc = 0;
+       smi.meta_rfc822_length = CCC->redirect_len;
+       saved_rfc822_version = CCC->redirect_buffer;
+       CCC->redirect_buffer = NULL;
+       CCC->redirect_len = 0;
+       CCC->redirect_alloc = 0;
 
        PutMetaData(&smi);
 
@@ -2536,7 +2582,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
         * message, we want to BYPASS saving the sender's copy (because there
         * is no local sender; it would otherwise go to the Trashcan).
         */
-       if ((!CC->internal_pgm) || (recps == NULL)) {
+       if ((!CCC->internal_pgm) || (recps == NULL)) {
                if (CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 1, msg) != 0) {
                        lprintf(CTDL_ERR, "ERROR saving message pointer!\n");
                        CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg);
@@ -2561,9 +2607,9 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
 
        /* Bump this user's messages posted counter. */
        lprintf(CTDL_DEBUG, "Updating user\n");
-       lgetuser(&CC->user, CC->curr_user);
-       CC->user.posted = CC->user.posted + 1;
-       lputuser(&CC->user);
+       lgetuser(&CCC->user, CCC->curr_user);
+       CCC->user.posted = CCC->user.posted + 1;
+       lputuser(&CCC->user);
 
        /* If this is private, local mail, make a copy in the
         * recipient's mailbox and bump the reference count.
@@ -2644,7 +2690,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
                        snprintf(submit_filename, sizeof submit_filename,
                                         "%s/netmail.%04lx.%04x.%04x",
                                         ctdl_netin_dir,
-                                        (long) getpid(), CC->cs_pid, ++seqnum);
+                                        (long) getpid(), CCC->cs_pid, ++seqnum);
                        network_fp = fopen(submit_filename, "wb+");
                        if (network_fp != NULL) {
                                fwrite(smr.ser, smr.len, 1, network_fp);
@@ -2661,7 +2707,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
 
        /* Go back to the room we started from */
        lprintf(CTDL_DEBUG, "Returning to original room %s\n", hold_rm);
-       if (strcasecmp(hold_rm, CC->room.QRname))
+       if (strcasecmp(hold_rm, CCC->room.QRname))
                usergoto(hold_rm, 0, 1, NULL, NULL);
 
        /* For internet mail, generate delivery instructions.
@@ -2706,7 +2752,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
        /*
         * Any addresses to harvest for someone's address book?
         */
-       if ( (CC->logged_in) && (recps != NULL) ) {
+       if ( (CCC->logged_in) && (recps != NULL) ) {
                collected_addresses = harvest_collected_addresses(msg);
        }
 
@@ -2716,7 +2762,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
                        malloc(sizeof(struct addresses_to_be_filed));
                aptr->next = atbf;
                MailboxName(actual_rm, sizeof actual_rm,
-                       &CC->user, USERCONTACTSROOM);
+                       &CCC->user, USERCONTACTSROOM);
                aptr->roomname = strdup(actual_rm);
                aptr->collected_addresses = collected_addresses;
                atbf = aptr;
@@ -2796,7 +2842,7 @@ void quickie_message(char *from, char *fromaddr, char *to, char *room, char *tex
        msg->cm_fields['N'] = strdup(NODENAME);
        if (to != NULL) {
                msg->cm_fields['R'] = strdup(to);
-               recp = validate_recipients(to);
+               recp = validate_recipients(to, NULL, 0);
        }
        if (subject != NULL) {
                msg->cm_fields['U'] = strdup(subject);
@@ -3045,13 +3091,59 @@ 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) {
+int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, 
+                                         size_t n, 
+                                         const char* RemoteIdentifier,
+                                         int PostPublic) {
        int ra;
 
-       if (!(CC->logged_in)) {
+       if (!(CC->logged_in) && 
+           (PostPublic == POST_LOGGED_IN)) {
                snprintf(errmsgbuf, n, "Not logged in.");
                return (ERROR + NOT_LOGGED_IN);
        }
+       else if (PostPublic == CHECK_EXISTANCE) {
+               return (0); // We're Evaling whether a recipient exists
+       }
+       else if (!(CC->logged_in)) {
+               if ((CC->room.QRflags & QR_READONLY)) {
+                       snprintf(errmsgbuf, n, "Not logged in.");
+                       return (ERROR + NOT_LOGGED_IN);
+               }
+               if (CC->room.QRflags2 & QR2_MODERATED) {
+                       snprintf(errmsgbuf, n, "Not logged in Moderation feature not yet implemented!");
+                       return (ERROR + NOT_LOGGED_IN);
+               }
+               if (CC->room.QRflags2 & QR2_SMTP_PUBLIC == 0){
+                       SpoolControl *sc;
+                       char filename[SIZ];
+                       int found;
+
+                       if (RemoteIdentifier == NULL)
+                       {
+                               snprintf(errmsgbuf, n, "Need sender to permit access.");
+                               return (ERROR + USERNAME_REQUIRED);
+                       }
+
+                       assoc_file_name(filename, sizeof filename, &CC->room, ctdl_netcfg_dir);
+                       begin_critical_section(S_NETCONFIGS);
+                       if (!read_spoolcontrol_file(&sc, filename))
+                       {
+                               end_critical_section(S_NETCONFIGS);
+                               snprintf(errmsgbuf, n, "No Subscribers found.");
+                               return (ERROR + NO_SUCH_USER);
+                       }
+                       end_critical_section(S_NETCONFIGS);
+                       found = is_recipient (sc, RemoteIdentifier);
+                       free_spoolcontrol_struct(&sc);
+                       if (found)
+                               return (0);
+                       else
+                               return (ERROR + NO_SUCH_USER);
+               }
+               return (0);
+
+       }
 
        if ((CC->user.axlevel < 2)
            && ((CC->room.QRflags & QR_MAILBOX) == 0)) {
@@ -3103,7 +3195,9 @@ int CtdlCheckInternetMailPermission(struct ctdluser *who) {
  *
  * Caller needs to free the result using free_recipients()
  */
-struct recptypes *validate_recipients(char *supplied_recipients) {
+struct recptypes *validate_recipients(char *supplied_recipients, 
+                                     const char *RemoteIdentifier, 
+                                     int Flags) {
        struct recptypes *ret;
        char *recipients = NULL;
        char this_recp[256];
@@ -3115,6 +3209,9 @@ struct recptypes *validate_recipients(char *supplied_recipients) {
        int invalid;
        struct ctdluser tempUS;
        struct ctdlroom tempQR;
+       struct ctdlroom tempQR2;
+       int err = 0;
+       char errmsg[SIZ];
        int in_quotes = 0;
 
        /* Initialize */
@@ -3223,11 +3320,33 @@ struct recptypes *validate_recipients(char *supplied_recipients) {
                                }
                                else if ( (!strncasecmp(this_recp, "room_", 5))
                                      && (!getroom(&tempQR, &this_recp_cooked[5])) ) {
-                                       ++ret->num_room;
-                                       if (!IsEmptyStr(ret->recp_room)) {
-                                               strcat(ret->recp_room, "|");
+
+                                       /* Save room so we can restore it later */
+                                       tempQR2 = CC->room;
+                                       CC->room = tempQR;
+                                       
+                                       /* Check permissions to send mail to this room */
+                                       err = CtdlDoIHavePermissionToPostInThisRoom(errmsg, 
+                                                                                   sizeof errmsg, 
+                                                                                   RemoteIdentifier,
+                                                                                   Flags);
+                                       if (err)
+                                       {
+                                               cprintf("%d %s\n", err, errmsg);
+                                               ++ret->num_error;
+                                               invalid = 1;
+                                       } 
+                                       else {
+                                               ++ret->num_room;
+                                               if (!IsEmptyStr(ret->recp_room)) {
+                                                       strcat(ret->recp_room, "|");
+                                               }
+                                               strcat(ret->recp_room, &this_recp_cooked[5]);
                                        }
-                                       strcat(ret->recp_room, &this_recp_cooked[5]);
+                                       
+                                       /* Restore room in case something needs it */
+                                       CC->room = tempQR2;
+
                                }
                                else {
                                        ++ret->num_error;
@@ -3388,7 +3507,7 @@ void cmd_ent0(char *entargs)
 
        /* first check to make sure the request is valid. */
 
-       err = CtdlDoIHavePermissionToPostInThisRoom(errmsg, sizeof errmsg);
+       err = CtdlDoIHavePermissionToPostInThisRoom(errmsg, sizeof errmsg, NULL, POST_LOGGED_IN);
        if (err)
        {
                cprintf("%d %s\n", err, errmsg);
@@ -3456,14 +3575,14 @@ void cmd_ent0(char *entargs)
                        strcpy(bcc, "");
                }
 
-               valid_to = validate_recipients(recp);
+               valid_to = validate_recipients(recp, NULL, 0);
                if (valid_to->num_error > 0) {
                        cprintf("%d Invalid recipient (To)\n", ERROR + NO_SUCH_USER);
                        free_recipients(valid_to);
                        return;
                }
 
-               valid_cc = validate_recipients(cc);
+               valid_cc = validate_recipients(cc, NULL, 0);
                if (valid_cc->num_error > 0) {
                        cprintf("%d Invalid recipient (CC)\n", ERROR + NO_SUCH_USER);
                        free_recipients(valid_to);
@@ -3471,7 +3590,7 @@ void cmd_ent0(char *entargs)
                        return;
                }
 
-               valid_bcc = validate_recipients(bcc);
+               valid_bcc = validate_recipients(bcc, NULL, 0);
                if (valid_bcc->num_error > 0) {
                        cprintf("%d Invalid recipient (BCC)\n", ERROR + NO_SUCH_USER);
                        free_recipients(valid_to);
@@ -3598,7 +3717,7 @@ void cmd_ent0(char *entargs)
                strcat(all_recps, bcc);
        }
        if (!IsEmptyStr(all_recps)) {
-               valid = validate_recipients(all_recps);
+               valid = validate_recipients(all_recps, NULL, 0);
        }
        else {
                valid = NULL;
@@ -4187,7 +4306,8 @@ void CtdlWriteObject(char *req_room,              /* Room to stuff it in */
                CtdlEncodeBase64(
                        &encoded_message[strlen(encoded_message)],
                        raw_message,
-                       (int)raw_length
+                       (int)raw_length,
+                       0
                );
        }
        else {
@@ -4315,7 +4435,7 @@ int CtdlIsMe(char *addr, int addr_buf_len)
        struct recptypes *recp;
        int i;
 
-       recp = validate_recipients(addr);
+       recp = validate_recipients(addr, NULL, 0);
        if (recp == NULL) return(0);
 
        if (recp->num_local == 0) {