Don't register commands twice, only register them before threading begins.
[citadel.git] / citadel / msgbase.c
index 7b4873cee126a5ee59332e3f4c5e958416357fc7..9f4c5f222be5cae08cb154852d5cbe05564cf9e7 100644 (file)
@@ -2,7 +2,22 @@
  * $Id$
  *
  * Implements the message store.
+ * 
+ * Copyright (c) 1987-2009 by the citadel.org team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
  *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include "sysdep.h"
@@ -281,6 +296,28 @@ void headers_listing(long msgnum, void *userdata)
        CtdlFreeMessage(msg);
 }
 
+/*
+ * Back end for the MSGS command: output EUID header.
+ */
+void headers_euid(long msgnum, void *userdata)
+{
+       struct CtdlMessage *msg;
+
+       msg = CtdlFetchMessage(msgnum, 0);
+       if (msg == NULL) {
+               cprintf("%ld||\n", msgnum);
+               return;
+       }
+
+       cprintf("%ld|%s|\n",
+               msgnum,
+               (msg->cm_fields['U'] ? msg->cm_fields['U'] : "")
+       );
+       CtdlFreeMessage(msg);
+}
+
+
+
 
 
 /* Determine if a given message matches the fields in a message template.
@@ -565,7 +602,7 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums,
 int CtdlForEachMessage(int mode, long ref, char *search_string,
                        char *content_type,
                        struct CtdlMessage *compare,
-                       void (*CallBack) (long, void *),
+                        ForEachMsgCallback CallBack,
                        void *userdata)
 {
 
@@ -593,7 +630,7 @@ int CtdlForEachMessage(int mode, long ref, char *search_string,
        }
 
        /* Learn about the user and room in question */
-       getuser(&CC->user, CC->curr_user);
+       CtdlGetUser(&CC->user, CC->curr_user);
        CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
 
        /* Load the message list */
@@ -758,14 +795,26 @@ void cmd_msgs(char *cmdbuf)
        int i;
        int with_template = 0;
        struct CtdlMessage *template = NULL;
-       int with_headers = 0;
        char search_string[1024];
+       ForEachMsgCallback CallBack;
 
        extract_token(which, cmdbuf, 0, '|', sizeof which);
        cm_ref = extract_int(cmdbuf, 1);
        extract_token(search_string, cmdbuf, 1, '|', sizeof search_string);
        with_template = extract_int(cmdbuf, 2);
-       with_headers = extract_int(cmdbuf, 3);
+       switch (extract_int(cmdbuf, 3))
+       {
+       default:
+       case MSG_HDRS_BRIEF:
+               CallBack = simple_listing;
+               break;
+       case MSG_HDRS_ALL:
+               CallBack = headers_listing;
+               break;
+       case MSG_HDRS_EUID:
+               CallBack = headers_euid;
+               break;
+       }
 
        strcat(which, "   ");
        if (!strncasecmp(which, "OLD", 3))
@@ -821,13 +870,12 @@ void cmd_msgs(char *cmdbuf)
        }
 
        CtdlForEachMessage(mode,
-                       ( (mode == MSGS_SEARCH) ? 0 : cm_ref ),
-                       ( (mode == MSGS_SEARCH) ? search_string : NULL ),
-                       NULL,
-                       template,
-                       (with_headers ? headers_listing : simple_listing),
-                       NULL
-       );
+                          ( (mode == MSGS_SEARCH) ? 0 : cm_ref ),
+                          ( (mode == MSGS_SEARCH) ? search_string : NULL ),
+                          NULL,
+                          template,
+                          CallBack,
+                          NULL);
        if (template != NULL) CtdlFreeMessage(template);
        cprintf("000\n");
 }
@@ -1431,6 +1479,16 @@ void extract_encapsulated_message(char *name, char *filename, char *partnum, cha
 
 
 
+
+
+int CtdlDoIHavePermissionToReadMessagesInThisRoom(void) {
+       if ((!(CC->logged_in)) && (!(CC->internal_pgm))) {
+               return(om_not_logged_in);
+       }
+       return(om_ok);
+}
+
+
 /*
  * Get a message off disk.  (returns om_* values found in msgbase.h)
  * 
@@ -1441,21 +1499,29 @@ int CtdlOutputMsg(long msg_num,         /* message number (local) to fetch */
                  int do_proto,         /* do Citadel protocol responses? */
                  int crlf,             /* Use CRLF newlines instead of LF? */
                  char *section,        /* NULL or a message/rfc822 section */
-                 int flags             /* should the bessage be exported clean? */
+                 int flags             /* various flags; see msgbase.h */
 ) {
        struct CtdlMessage *TheMessage = NULL;
        int retcode = om_no_such_msg;
        struct encapmsg encap;
+       int r;
 
-       CtdlLogPrintf(CTDL_DEBUG, "CtdlOutputMsg() msgnum=%ld, mode=%d, section=%s\n", 
+       CtdlLogPrintf(CTDL_DEBUG, "CtdlOutputMsg(msgnum=%ld, mode=%d, section=%s)\n", 
                msg_num, mode,
                (section ? section : "<>")
        );
 
-       if ((!(CC->logged_in)) && (!(CC->internal_pgm))) {
-               if (do_proto) cprintf("%d Not logged in.\n",
-                       ERROR + NOT_LOGGED_IN);
-               return(om_not_logged_in);
+       r = CtdlDoIHavePermissionToReadMessagesInThisRoom();
+       if (r != om_ok) {
+               if (do_proto) {
+                       if (r == om_not_logged_in) {
+                               cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN);
+                       }
+                       else {
+                               cprintf("%d An unknown error has occurred.\n", ERROR);
+                       }
+               }
+               return(r);
        }
 
        /* FIXME: check message id against msglist for this room */
@@ -1707,6 +1773,13 @@ int CtdlOutputPreLoadedMsg(
                return(om_no_such_msg);
        }
 
+       /* Suppress envelope recipients if required to avoid disclosing BCC addresses.
+        * Pad it with spaces in order to avoid changing the RFC822 length of the message.
+        */
+       if ( (flags & SUPPRESS_ENV_TO) && (TheMessage->cm_fields['V'] != NULL) ) {
+               memset(TheMessage->cm_fields['V'], ' ', strlen(TheMessage->cm_fields['V']));
+       }
+               
        /* Are we downloading a MIME component? */
        if (mode == MT_DOWNLOAD) {
                if (TheMessage->cm_format_type != FMT_RFC822) {
@@ -1814,7 +1887,7 @@ int CtdlOutputPreLoadedMsg(
                      if (haschar(TheMessage->cm_fields['N'], '.') == 0) {
                        suppress_f = 1;
                }
-               
+
                /* Now spew the header fields in the order we like them. */
                safestrncpy(allkeys, FORDER, sizeof allkeys);
                for (i=0; i<strlen(allkeys); ++i) {
@@ -2303,7 +2376,7 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms
        if (num_newmsgs > 1) supplied_msg = NULL;
 
        /* Now the regular stuff */
-       if (lgetroom(&CC->room,
+       if (CtdlGetRoomLock(&CC->room,
           ((roomname != NULL) ? roomname : CC->room.QRname) )
           != 0) {
                CtdlLogPrintf(CTDL_ERR, "No such room <%s>\n", roomname);
@@ -2370,7 +2443,7 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms
 
        /* Update the highest-message pointer and unlock the room. */
        CC->room.QRhighest = highest_msg;
-       lputroom(&CC->room);
+       CtdlPutRoomLock(&CC->room);
 
        /* Perform replication checks if necessary */
        if ( (DoesThisRoomNeedEuidIndexing(&CC->room)) && (do_repl_check) ) {
@@ -2411,7 +2484,7 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms
        PerformRoomHooks(&CC->room);
 
        /* Go back to the room we were in before we wandered here... */
-       getroom(&CC->room, hold_rm);
+       CtdlGetRoom(&CC->room, hold_rm);
 
        /* Bump the reference count for all messages which were merged */
        for (i=0; i<num_msgs_to_be_merged; ++i) {
@@ -2765,8 +2838,8 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
 
        CtdlLogPrintf(CTDL_DEBUG, "Final selection: %s\n", actual_rm);
        if (strcasecmp(actual_rm, CCC->room.QRname)) {
-               /* getroom(&CCC->room, actual_rm); */
-               usergoto(actual_rm, 0, 1, NULL, NULL);
+               /* CtdlGetRoom(&CCC->room, actual_rm); */
+               CtdlUserGoto(actual_rm, 0, 1, NULL, NULL);
        }
 
        /*
@@ -2860,9 +2933,9 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
 
        /* Bump this user's messages posted counter. */
        CtdlLogPrintf(CTDL_DEBUG, "Updating user\n");
-       lgetuser(&CCC->user, CCC->curr_user);
+       CtdlGetUserLock(&CCC->user, CCC->curr_user);
        CCC->user.posted = CCC->user.posted + 1;
-       lputuser(&CCC->user);
+       CtdlPutUserLock(&CCC->user);
 
        /* Decide where bounces need to be delivered */
        if ((recps != NULL) && (recps->bounce_to != NULL)) {
@@ -2884,10 +2957,10 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,     /* message to save */
                                        '|', sizeof recipient);
                CtdlLogPrintf(CTDL_DEBUG, "Delivering private local mail to <%s>\n",
                        recipient);
-               if (getuser(&userbuf, recipient) == 0) {
+               if (CtdlGetUser(&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);
+                       CtdlMailboxName(actual_rm, sizeof actual_rm, &userbuf, MAILROOM);
                        CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 0, msg);
                        BumpNewMailCounter(userbuf.usernum);
                        if (!IsEmptyStr(config.c_funambol_host) || !IsEmptyStr(config.c_pager_program)) {
@@ -2970,7 +3043,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
        /* Go back to the room we started from */
        CtdlLogPrintf(CTDL_DEBUG, "Returning to original room %s\n", hold_rm);
        if (strcasecmp(hold_rm, CCC->room.QRname))
-               usergoto(hold_rm, 0, 1, NULL, NULL);
+               CtdlUserGoto(hold_rm, 0, 1, NULL, NULL);
 
        /* For internet mail, generate delivery instructions.
         * Yes, this is recursive.  Deal with it.  Infinite recursion does
@@ -3025,7 +3098,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
        if (collected_addresses != NULL) {
                aptr = (struct addresses_to_be_filed *)
                        malloc(sizeof(struct addresses_to_be_filed));
-               MailboxName(actual_rm, sizeof actual_rm,
+               CtdlMailboxName(actual_rm, sizeof actual_rm,
                        &CCC->user, USERCONTACTSROOM);
                aptr->roomname = strdup(actual_rm);
                aptr->collected_addresses = collected_addresses;
@@ -3073,6 +3146,10 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,      /* message to save */
 
 
 
+void aide_message (char *text, char *subject)
+{
+       quickie_message("Citadel",NULL,NULL,AIDEROOM,text,FMT_CITADEL,subject);
+}
 
 
 /*
@@ -3582,7 +3659,7 @@ struct recptypes *validate_recipients(char *supplied_recipients,
                                        strcat(ret->recp_room, this_recp);
                                }
                                else if ( (!strncasecmp(this_recp, "room_", 5))
-                                     && (!getroom(&tempQR, &this_recp_cooked[5])) ) {
+                                     && (!CtdlGetRoom(&tempQR, &this_recp_cooked[5])) ) {
 
                                        /* Save room so we can restore it later */
                                        tempQR2 = CC->room;
@@ -3611,7 +3688,7 @@ struct recptypes *validate_recipients(char *supplied_recipients,
                                        CC->room = tempQR2;
 
                                }
-                               else if (getuser(&tempUS, this_recp) == 0) {
+                               else if (CtdlGetUser(&tempUS, this_recp) == 0) {
                                        ++ret->num_local;
                                        strcpy(this_recp, tempUS.fullname);
                                        if (!IsEmptyStr(ret->recp_local)) {
@@ -3619,7 +3696,7 @@ struct recptypes *validate_recipients(char *supplied_recipients,
                                        }
                                        strcat(ret->recp_local, this_recp);
                                }
-                               else if (getuser(&tempUS, this_recp_cooked) == 0) {
+                               else if (CtdlGetUser(&tempUS, this_recp_cooked) == 0) {
                                        ++ret->num_local;
                                        strcpy(this_recp, tempUS.fullname);
                                        if (!IsEmptyStr(ret->recp_local)) {
@@ -4072,7 +4149,7 @@ int CtdlDeleteMessages(char *room_name,           /* which room */
                room_name, num_dmsgnums, content_type);
 
        /* get room record, obtaining a lock... */
-       if (lgetroom(&qrbuf, room_name) != 0) {
+       if (CtdlGetRoomLock(&qrbuf, room_name) != 0) {
                CtdlLogPrintf(CTDL_ERR, "CtdlDeleteMessages(): Room <%s> not found\n",
                        room_name);
                if (need_to_free_re) regfree(&re);
@@ -4129,7 +4206,7 @@ int CtdlDeleteMessages(char *room_name,           /* which room */
 
                qrbuf.QRhighest = msglist[num_msgs - 1];
        }
-       lputroom(&qrbuf);
+       CtdlPutRoomLock(&qrbuf);
 
        /* Go through the messages we pulled out of the index, and decrement
         * their reference counts by 1.  If this is the only room the message
@@ -4246,7 +4323,7 @@ void cmd_move(char *args)
        targ[ROOMNAMELEN - 1] = 0;
        is_copy = extract_int(args, 2);
 
-       if (getroom(&qtemp, targ) != 0) {
+       if (CtdlGetRoom(&qtemp, targ) != 0) {
                cprintf("%d '%s' does not exist.\n", ERROR + ROOM_NOT_FOUND, targ);
                return;
        }
@@ -4256,7 +4333,7 @@ void cmd_move(char *args)
                return;
        }
 
-       getuser(&CC->user, CC->curr_user);
+       CtdlGetUser(&CC->user, CC->curr_user);
        CtdlRoomAccess(&qtemp, &CC->user, &ra, NULL);
 
        /* Check for permission to perform this operation.
@@ -4541,7 +4618,7 @@ void CtdlWriteObject(char *req_room,                      /* Room to stuff it in */
        char *encoded_message = NULL;
 
        if (is_mailbox != NULL) {
-               MailboxName(roomname, sizeof roomname, is_mailbox, req_room);
+               CtdlMailboxName(roomname, sizeof roomname, is_mailbox, req_room);
        }
        else {
                safestrncpy(roomname, req_room, sizeof(roomname));
@@ -4600,8 +4677,8 @@ void CtdlWriteObject(char *req_room,                      /* Room to stuff it in */
        msg->cm_fields['M'] = encoded_message;
 
        /* Create the requested room if we have to. */
-       if (getroom(&qrbuf, roomname) != 0) {
-               create_room(roomname, 
+       if (CtdlGetRoom(&qrbuf, roomname) != 0) {
+               CtdlCreateRoom(roomname, 
                        ( (is_mailbox != NULL) ? 5 : 3 ),
                        "", 0, 1, 0, VIEW_BBS);
        }
@@ -4636,8 +4713,8 @@ char *CtdlGetSysConfig(char *sysconfname) {
        char buf[SIZ];
        
        strcpy(hold_rm, CC->room.QRname);
-       if (getroom(&CC->room, SYSCONFIGROOM) != 0) {
-               getroom(&CC->room, hold_rm);
+       if (CtdlGetRoom(&CC->room, SYSCONFIGROOM) != 0) {
+               CtdlGetRoom(&CC->room, hold_rm);
                return NULL;
        }
 
@@ -4664,7 +4741,7 @@ char *CtdlGetSysConfig(char *sysconfname) {
                }
        }
 
-       getroom(&CC->room, hold_rm);
+       CtdlGetRoom(&CC->room, hold_rm);
 
        if (conf != NULL) do {
                extract_token(buf, conf, 0, '\n', sizeof buf);
@@ -4734,18 +4811,20 @@ void cmd_isme(char *argbuf) {
 
 CTDL_MODULE_INIT(msgbase)
 {
-       CtdlRegisterProtoHook(cmd_msgs, "MSGS", "Output a list of messages in the current room");
-       CtdlRegisterProtoHook(cmd_msg0, "MSG0", "Output a message in plain text format");
-       CtdlRegisterProtoHook(cmd_msg2, "MSG2", "Output a message in RFC822 format");
-       CtdlRegisterProtoHook(cmd_msg3, "MSG3", "Output a message in raw format (deprecated)");
-       CtdlRegisterProtoHook(cmd_msg4, "MSG4", "Output a message in the client's preferred format");
-       CtdlRegisterProtoHook(cmd_msgp, "MSGP", "Select preferred format for MSG4 output");
-       CtdlRegisterProtoHook(cmd_opna, "OPNA", "Open an attachment for download");
-       CtdlRegisterProtoHook(cmd_dlat, "DLAT", "Download an attachment");
-       CtdlRegisterProtoHook(cmd_ent0, "ENT0", "Enter a message");
-       CtdlRegisterProtoHook(cmd_dele, "DELE", "Delete a message");
-       CtdlRegisterProtoHook(cmd_move, "MOVE", "Move or copy a message to another room");
-       CtdlRegisterProtoHook(cmd_isme, "ISME", "Determine whether an email address belongs to a user");
+       if (!threading) {
+               CtdlRegisterProtoHook(cmd_msgs, "MSGS", "Output a list of messages in the current room");
+               CtdlRegisterProtoHook(cmd_msg0, "MSG0", "Output a message in plain text format");
+               CtdlRegisterProtoHook(cmd_msg2, "MSG2", "Output a message in RFC822 format");
+               CtdlRegisterProtoHook(cmd_msg3, "MSG3", "Output a message in raw format (deprecated)");
+               CtdlRegisterProtoHook(cmd_msg4, "MSG4", "Output a message in the client's preferred format");
+               CtdlRegisterProtoHook(cmd_msgp, "MSGP", "Select preferred format for MSG4 output");
+               CtdlRegisterProtoHook(cmd_opna, "OPNA", "Open an attachment for download");
+               CtdlRegisterProtoHook(cmd_dlat, "DLAT", "Download an attachment");
+               CtdlRegisterProtoHook(cmd_ent0, "ENT0", "Enter a message");
+               CtdlRegisterProtoHook(cmd_dele, "DELE", "Delete a message");
+               CtdlRegisterProtoHook(cmd_move, "MOVE", "Move or copy a message to another room");
+               CtdlRegisterProtoHook(cmd_isme, "ISME", "Determine whether an email address belongs to a user");
+       }
 
         /* return our Subversion id for the Log */
        return "$Id$";