]> code.citadel.org Git - citadel.git/blobdiff - citadel/msgbase.c
Server-side changes to allow users to submit messages
[citadel.git] / citadel / msgbase.c
index 099af20dcd920054873b3340abe9ecbc40864355..f5a8da0e42d4b00a14c7e38816323793750de3a6 100644 (file)
@@ -29,6 +29,8 @@
 #include <errno.h>
 #include <stdarg.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <regex.h>
 #include "citadel.h"
 #include "server.h"
 #include "serv_extensions.h"
@@ -243,22 +245,6 @@ int alias(char *name)
 }
 
 
-void get_mm(void)
-{
-       FILE *fp;
-
-       fp = fopen(file_citadel_control, "r");
-       if (fp == NULL) {
-               lprintf(CTDL_CRIT, "Cannot open %s: %s\n",
-                               file_citadel_control,
-                               strerror(errno));
-               exit(errno);
-       }
-       fread((char *) &CitControl, sizeof(struct CitControl), 1, fp);
-       fclose(fp);
-}
-
-
 /*
  * Back end for the MSGS command: output message number only.
  */
@@ -532,15 +518,20 @@ int CtdlForEachMessage(int mode, long ref, char *search_string,
        int num_processed = 0;
        long thismsg;
        struct MetaData smi;
-       struct CtdlMessage *msg;
+       struct CtdlMessage *msg = NULL;
        int is_seen = 0;
        long lastold = 0L;
        int printed_lastold = 0;
        int num_search_msgs = 0;
        long *search_msgs = NULL;
+       regex_t re;
+       regmatch_t pm;
+
+       if (content_type) if (strlen(content_type) > 0) {
+               regcomp(&re, content_type, 0);
+       }
 
        /* Learn about the user and room in question */
-       get_mm();
        getuser(&CC->user, CC->curr_user);
        CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
 
@@ -577,7 +568,8 @@ int CtdlForEachMessage(int mode, long ref, char *search_string,
                         */
                        GetMetaData(&smi, msglist[a]);
 
-                       if (strcasecmp(smi.meta_content_type, content_type)) {
+                       /* if (strcasecmp(smi.meta_content_type, content_type)) { old non-regex way */
+                       if (regexec(&re, smi.meta_content_type, 1, &pm, 0) != 0) {
                                msglist[a] = 0L;
                        }
                }
@@ -742,6 +734,9 @@ void cmd_msgs(char *cmdbuf)
                template = (struct CtdlMessage *)
                        malloc(sizeof(struct CtdlMessage));
                memset(template, 0, sizeof(struct CtdlMessage));
+               template->cm_magic = CTDLMESSAGE_MAGIC;
+               template->cm_anon_type = MES_NORMAL;
+
                while(client_getln(buf, sizeof buf), strcmp(buf,"000")) {
                        extract_token(tfield, buf, 0, '|', sizeof tfield);
                        extract_token(tvalue, buf, 1, '|', sizeof tvalue);
@@ -1109,7 +1104,11 @@ void CtdlFreeMessage(struct CtdlMessage *msg)
 {
        int i;
 
-       if (is_valid_message(msg) == 0) return;
+       if (is_valid_message(msg) == 0) 
+       {
+               if (msg != NULL) free (msg);
+               return;
+       }
 
        for (i = 0; i < 256; ++i)
                if (msg->cm_fields[i] != NULL) {
@@ -1258,7 +1257,6 @@ void choose_preferred(char *name, char *filename, char *partnum, char *disp,
        if (ma->is_ma > 0) {
                for (i=0; i<num_tokens(CC->preferred_formats, '|'); ++i) {
                        extract_token(buf, CC->preferred_formats, i, '|', sizeof buf);
-                       lprintf(CTDL_DEBUG, "Is <%s> == <%s> ??\n", buf, cbtype);
                        if ( (!strcasecmp(buf, cbtype)) && (!ma->freeze) ) {
                                if (i < ma->chosen_pref) {
                                        safestrncpy(ma->chosen_part, partnum, sizeof ma->chosen_part);
@@ -1902,7 +1900,7 @@ void cmd_msg2(char *cmdbuf)
 void cmd_msg3(char *cmdbuf)
 {
        long msgnum;
-       struct CtdlMessage *msg;
+       struct CtdlMessage *msg = NULL;
        struct ser_ret smr;
 
        if (CC->internal_pgm == 0) {
@@ -2567,10 +2565,35 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,     /* message to save */
                lprintf(CTDL_DEBUG, "Delivering private local mail to <%s>\n",
                        recipient);
                if (getuser(&userbuf, recipient) == 0) {
+                       // Add a flag so the Funambol module knows its mail
+                       msg->cm_fields['W'] = strdup(recipient);
                        MailboxName(actual_rm, sizeof actual_rm,
                                        &userbuf, MAILROOM);
                        CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 0, msg);
                        BumpNewMailCounter(userbuf.usernum);
+                       if (strlen(config.c_funambol_host) > 0) {
+                       /* Generate a instruction message for the Funambol notification
+                          server, in the same style as the SMTP queue */
+                          instr = malloc(SIZ * 2);
+                          snprintf(instr, SIZ * 2,
+                       "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n"
+                       "bounceto|%s@%s\n",
+                       SPOOLMIME, newmsgid, (long)time(NULL),
+                       msg->cm_fields['A'], msg->cm_fields['N']
+                       );
+
+                          imsg = malloc(sizeof(struct CtdlMessage));
+                          memset(imsg, 0, sizeof(struct CtdlMessage));
+                          imsg->cm_magic = CTDLMESSAGE_MAGIC;
+                          imsg->cm_anon_type = MES_NORMAL;
+                          imsg->cm_format_type = FMT_RFC822;
+                          imsg->cm_fields['A'] = strdup("Citadel");
+                          imsg->cm_fields['J'] = strdup("do not journal");
+                          imsg->cm_fields['M'] = instr;
+                          imsg->cm_fields['W'] = strdup(recipient);
+                          CtdlSubmitMsg(imsg, NULL, FNBL_QUEUE_ROOM);
+                          CtdlFreeMessage(imsg);
+                       }
                }
                else {
                        lprintf(CTDL_DEBUG, "No user <%s>\n", recipient);
@@ -2887,12 +2910,13 @@ struct CtdlMessage *CtdlMakeMessage(
        int type,                       /* see MES_ types in header file */
        int format_type,                /* variformat, plain text, MIME... */
        char *fake_name,                /* who we're masquerading as */
+       char *my_email,                 /* which of my email addresses to use (empty is ok) */
        char *subject,                  /* Subject (optional) */
        char *supplied_euid,            /* ...or NULL if this is irrelevant */
        char *preformatted_text         /* ...or NULL to read text from client */
 ) {
-       char dest_node[SIZ];
-       char buf[SIZ];
+       char dest_node[256];
+       char buf[1024];
        struct CtdlMessage *msg;
 
        msg = malloc(sizeof(struct CtdlMessage));
@@ -2938,7 +2962,10 @@ struct CtdlMessage *CtdlMakeMessage(
                msg->cm_fields['D'] = strdup(dest_node);
        }
 
-       if ( (author == &CC->user) && (strlen(CC->cs_inet_email) > 0) ) {
+       if (strlen(my_email) > 0) {
+               msg->cm_fields['F'] = strdup(my_email);
+       }
+       else if ( (author == &CC->user) && (strlen(CC->cs_inet_email) > 0) ) {
                msg->cm_fields['F'] = strdup(CC->cs_inet_email);
        }
 
@@ -2972,8 +2999,7 @@ struct CtdlMessage *CtdlMakeMessage(
                msg->cm_fields['M'] = preformatted_text;
        }
        else {
-               msg->cm_fields['M'] = CtdlReadMessageBody("000",
-                                       config.c_maxmsglen, NULL, 0);
+               msg->cm_fields['M'] = CtdlReadMessageBody("000", config.c_maxmsglen, NULL, 0);
        }
 
        return(msg);
@@ -2986,6 +3012,7 @@ struct CtdlMessage *CtdlMakeMessage(
  * returns 0 on success.
  */
 int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, size_t n) {
+       int ra;
 
        if (!(CC->logged_in)) {
                snprintf(errmsgbuf, n, "Not logged in.");
@@ -2999,15 +3026,9 @@ int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, size_t n) {
                return (ERROR + HIGHER_ACCESS_REQUIRED);
        }
 
-       if ((CC->user.axlevel < 4)
-          && (CC->room.QRflags & QR_NETWORK)) {
-               snprintf(errmsgbuf, n, "Need net privileges to enter here.");
-               return (ERROR + HIGHER_ACCESS_REQUIRED);
-       }
-
-       if ((CC->user.axlevel < 6)
-          && (CC->room.QRflags & QR_READONLY)) {
-               snprintf(errmsgbuf, n, "Sorry, this is a read-only room.");
+       CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL);
+       if (!(ra & UA_POSTALLOWED)) {
+               snprintf(errmsgbuf, n, "Higher access is required to post in this room.");
                return (ERROR + HIGHER_ACCESS_REQUIRED);
        }
 
@@ -3245,10 +3266,10 @@ void cmd_ent0(char *entargs)
        char cc[SIZ];
        char bcc[SIZ];
        char supplied_euid[128];
-       char masquerade_as[SIZ];
        int anon_flag = 0;
        int format_type = 0;
-       char newusername[SIZ];
+       char newusername[256];
+       char newuseremail[256];
        struct CtdlMessage *msg;
        int anonymous = 0;
        char errmsg[SIZ];
@@ -3260,6 +3281,9 @@ void cmd_ent0(char *entargs)
        char subject[SIZ];
        int do_confirm = 0;
        long msgnum;
+       int i, j;
+       char buf[256];
+       int newuseremail_ok = 0;
 
        unbuffer_output();
 
@@ -3268,6 +3292,7 @@ void cmd_ent0(char *entargs)
        anon_flag = extract_int(entargs, 2);
        format_type = extract_int(entargs, 3);
        extract_token(subject, entargs, 4, '|', sizeof subject);
+       extract_token(newusername, entargs, 5, '|', sizeof newusername);
        do_confirm = extract_int(entargs, 6);
        extract_token(cc, entargs, 7, '|', sizeof cc);
        extract_token(bcc, entargs, 8, '|', sizeof bcc);
@@ -3280,30 +3305,61 @@ void cmd_ent0(char *entargs)
                        supplied_euid[0] = 0;
                        break;
        }
+       extract_token(newuseremail, entargs, 9, '|', sizeof newuseremail);
 
        /* first check to make sure the request is valid. */
 
        err = CtdlDoIHavePermissionToPostInThisRoom(errmsg, sizeof errmsg);
-       if (err) {
+       if (err)
+       {
                cprintf("%d %s\n", err, errmsg);
                return;
        }
 
        /* Check some other permission type things. */
 
-       if (post == 2) {
-               if (CC->user.axlevel < 6) {
-                       cprintf("%d You don't have permission to masquerade.\n",
-                               ERROR + HIGHER_ACCESS_REQUIRED);
-                       return;
+       if (strlen(newusername) == 0) {
+               strcpy(newusername, CC->user.fullname);
+       }
+       if (  (CC->user.axlevel < 6)
+          && (strcasecmp(newusername, CC->user.fullname))
+          && (strcasecmp(newusername, CC->cs_inet_fn))
+       ) {     
+               cprintf("%d You don't have permission to author messages as '%s'.\n",
+                       ERROR + HIGHER_ACCESS_REQUIRED,
+                       newusername
+               );
+               return;
+       }
+
+
+       if (strlen(newuseremail) == 0) {
+               newuseremail_ok = 1;
+       }
+
+       if (strlen(newuseremail) > 0) {
+               if (!strcasecmp(newuseremail, CC->cs_inet_email)) {
+                       newuseremail_ok = 1;
                }
-               extract_token(newusername, entargs, 5, '|', sizeof newusername);
-               memset(CC->fake_postname, 0, sizeof(CC->fake_postname) );
-               safestrncpy(CC->fake_postname, newusername,
-                       sizeof(CC->fake_postname) );
-               cprintf("%d ok\n", CIT_OK);
+               else if (strlen(CC->cs_inet_other_emails) > 0) {
+                       j = num_tokens(CC->cs_inet_other_emails, '|');
+                       for (i=0; i<j; ++i) {
+                               extract_token(buf, CC->cs_inet_other_emails, i, '|', sizeof buf);
+                               if (!strcasecmp(newuseremail, buf)) {
+                                       newuseremail_ok = 1;
+                               }
+                       }
+               }
+       }
+
+       if (!newuseremail_ok) {
+               cprintf("%d You don't have permission to author messages as '%s'.\n",
+                       ERROR + HIGHER_ACCESS_REQUIRED,
+                       newuseremail
+               );
                return;
        }
+
        CC->cs_flags |= CS_POSTING;
 
        /* In the Mail> room we have to behave a little differently --
@@ -3420,17 +3476,6 @@ void cmd_ent0(char *entargs)
        free(valid_cc);
        free(valid_bcc);
 
-       /* Handle author masquerading */
-       if (CC->fake_postname[0]) {
-               strcpy(masquerade_as, CC->fake_postname);
-       }
-       else if (CC->fake_username[0]) {
-               strcpy(masquerade_as, CC->fake_username);
-       }
-       else {
-               strcpy(masquerade_as, "");
-       }
-
        /* Read in the message from the client. */
        if (do_confirm) {
                cprintf("%d send message\n", START_CHAT_MODE);
@@ -3440,7 +3485,7 @@ void cmd_ent0(char *entargs)
 
        msg = CtdlMakeMessage(&CC->user, recp, cc,
                CC->room.QRname, anonymous, format_type,
-               masquerade_as, subject,
+               newusername, newuseremail, subject,
                ((strlen(supplied_euid) > 0) ? supplied_euid : NULL),
                NULL);
 
@@ -3490,7 +3535,6 @@ void cmd_ent0(char *entargs)
 
                CtdlFreeMessage(msg);
        }
-       CC->fake_postname[0] = '\0';
        if (valid != NULL) {
                free(valid);
        }
@@ -3506,10 +3550,9 @@ void cmd_ent0(char *entargs)
 int CtdlDeleteMessages(char *room_name,                /* which room */
                        long *dmsgnums,         /* array of msg numbers to be deleted */
                        int num_dmsgnums,       /* number of msgs to be deleted, or 0 for "any" */
-                       char *content_type      /* or "" for any */
+                       char *content_type      /* or "" for any.  regular expressions expected. */
 )
 {
-
        struct ctdlroom qrbuf;
        struct cdbdata *cdbfr;
        long *msglist = NULL;
@@ -3519,7 +3562,12 @@ int CtdlDeleteMessages(char *room_name,          /* which room */
        int num_deleted = 0;
        int delete_this;
        struct MetaData smi;
+       regex_t re;
+       regmatch_t pm;
 
+       if (content_type) if (strlen(content_type) > 0) {
+               regcomp(&re, content_type, 0);
+       }
        lprintf(CTDL_DEBUG, "CtdlDeleteMessages(%s, %d msgs, %s)\n",
                room_name, num_dmsgnums, content_type);
 
@@ -3562,8 +3610,7 @@ int CtdlDeleteMessages(char *room_name,           /* which room */
                                delete_this |= 0x02;
                        } else {
                                GetMetaData(&smi, msglist[i]);
-                               if (!strcasecmp(smi.meta_content_type,
-                                               content_type)) {
+                               if (regexec(&re, smi.meta_content_type, 1, &pm, 0) == 0) {
                                        delete_this |= 0x02;
                                }
                        }
@@ -3610,18 +3657,15 @@ int CtdlDeleteMessages(char *room_name,         /* which room */
  * the current room (returns 1 for yes, 0 for no)
  */
 int CtdlDoIHavePermissionToDeleteMessagesFromThisRoom(void) {
-       getuser(&CC->user, CC->curr_user);
-       if ((CC->user.axlevel < 6)
-           && (CC->user.usernum != CC->room.QRroomaide)
-           && ((CC->room.QRflags & QR_MAILBOX) == 0)
-           && (!(CC->internal_pgm))) {
-               return(0);
-       }
-       return(1);
+       int ra;
+       CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL);
+       if (ra & UA_DELETEALLOWED) return(1);
+       return(0);
 }
 
 
 
+
 /*
  * Delete message from current room
  */