Add aide message functionality that uses the UT table to protect the user from an...
[citadel.git] / citadel / msgbase.c
index 8cc816e8184a368e0a096ae6f6a6a94671035de7..568cefb2e06f6c57175510351cbf1b05acf5b049 100644 (file)
@@ -38,6 +38,9 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <regex.h>
+
+#include "md5.h"
+
 #include <libcitadel.h>
 #include "citadel.h"
 #include "server.h"
@@ -1654,7 +1657,9 @@ 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             /* various flags; see msgbase.h */
+                 int flags,            /* various flags; see msgbase.h */
+                 char **Author,
+                 char **Address
 ) {
        struct CitContext *CCC = CC;
        struct CtdlMessage *TheMessage = NULL;
@@ -1732,6 +1737,17 @@ int CtdlOutputMsg(long msg_num,          /* message number (local) to fetch */
                        *extract_encapsulated_message,
                        NULL, NULL, (void *)&encap, 0
                );
+
+               if ((Author != NULL) && (*Author == NULL))
+               {
+                       *Author = TheMessage->cm_fields['A'];
+                       TheMessage->cm_fields['A'] = NULL;
+               }
+               if ((Address != NULL) && (*Address == NULL))
+               {       
+                       *Address = TheMessage->cm_fields['F'];
+                       TheMessage->cm_fields['F'] = NULL;
+               }
                CtdlFreeMessage(TheMessage);
                TheMessage = NULL;
 
@@ -1762,6 +1778,17 @@ int CtdlOutputMsg(long msg_num,          /* message number (local) to fetch */
        /* Ok, output the message now */
        if (retcode == CIT_OK)
                retcode = CtdlOutputPreLoadedMsg(TheMessage, mode, headers_only, do_proto, crlf, flags);
+       if ((Author != NULL) && (*Author == NULL))
+       {
+               *Author = TheMessage->cm_fields['A'];
+               TheMessage->cm_fields['A'] = NULL;
+       }
+       if ((Address != NULL) && (*Address == NULL))
+       {       
+               *Address = TheMessage->cm_fields['F'];
+               TheMessage->cm_fields['F'] = NULL;
+       }
+
        CtdlFreeMessage(TheMessage);
 
        return(retcode);
@@ -1789,7 +1816,7 @@ char *qp_encode_email_addrs(char *source)
 
        if (source == NULL) return source;
        if (IsEmptyStr(source)) return source;
-       cit_backtrace();
+       if (MessageDebugEnabled != 0) cit_backtrace();
        MSG_syslog(LOG_DEBUG, "qp_encode_email_addrs: [%s]\n", source);
 
        AddrPtr = malloc (sizeof (long) * nAddrPtrMax);
@@ -2541,7 +2568,7 @@ void cmd_msg0(char *cmdbuf)
        msgid = extract_long(cmdbuf, 0);
        headers_only = extract_int(cmdbuf, 1);
 
-       CtdlOutputMsg(msgid, MT_CITADEL, headers_only, 1, 0, NULL, 0);
+       CtdlOutputMsg(msgid, MT_CITADEL, headers_only, 1, 0, NULL, 0, NULL, NULL);
        return;
 }
 
@@ -2557,7 +2584,7 @@ void cmd_msg2(char *cmdbuf)
        msgid = extract_long(cmdbuf, 0);
        headers_only = extract_int(cmdbuf, 1);
 
-       CtdlOutputMsg(msgid, MT_RFC822, headers_only, 1, 1, NULL, 0);
+       CtdlOutputMsg(msgid, MT_RFC822, headers_only, 1, 1, NULL, 0, NULL, NULL);
 }
 
 
@@ -2611,7 +2638,7 @@ void cmd_msg4(char *cmdbuf)
 
        msgid = extract_long(cmdbuf, 0);
        extract_token(section, cmdbuf, 1, '|', sizeof section);
-       CtdlOutputMsg(msgid, MT_MIME, 0, 1, 0, (section[0] ? section : NULL) , 0);
+       CtdlOutputMsg(msgid, MT_MIME, 0, 1, 0, (section[0] ? section : NULL) , 0, NULL, NULL);
 }
 
 
@@ -2644,7 +2671,7 @@ void cmd_opna(char *cmdbuf)
        extract_token(desired_section, cmdbuf, 1, '|', sizeof desired_section);
        safestrncpy(CC->download_desired_section, desired_section,
                sizeof CC->download_desired_section);
-       CtdlOutputMsg(msgid, MT_DOWNLOAD, 0, 1, 1, NULL, 0);
+       CtdlOutputMsg(msgid, MT_DOWNLOAD, 0, 1, 1, NULL, 0, NULL, NULL);
 }                      
 
 
@@ -2660,8 +2687,8 @@ void cmd_dlat(char *cmdbuf)
        extract_token(desired_section, cmdbuf, 1, '|', sizeof desired_section);
        safestrncpy(CC->download_desired_section, desired_section,
                sizeof CC->download_desired_section);
-       CtdlOutputMsg(msgid, MT_SPEW_SECTION, 0, 1, 1, NULL, 0);
-}                      
+       CtdlOutputMsg(msgid, MT_SPEW_SECTION, 0, 1, 1, NULL, 0, NULL, NULL);
+}
 
 
 /*
@@ -3465,18 +3492,16 @@ 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);
-}
-
-
 /*
  * Convenience function for generating small administrative messages.
  */
-void quickie_message(const char *from, const char *fromaddr, char *to, char *room, const char *text, 
-                    int format_type, const char *subject)
+void quickie_message(const char *from,
+                    const char *fromaddr,
+                    char *to,
+                    char *room,
+                    const char *text, 
+                    int format_type,
+                    const char *subject)
 {
        struct CtdlMessage *msg;
        struct recptypes *recp = NULL;
@@ -3517,6 +3542,72 @@ void quickie_message(const char *from, const char *fromaddr, char *to, char *roo
        if (recp != NULL) free_recipients(recp);
 }
 
+void flood_protect_quickie_message(const char *from,
+                                  const char *fromaddr,
+                                  char *to,
+                                  char *room,
+                                  const char *text, 
+                                  int format_type,
+                                  const char *subject,
+                                  int nCriterions,
+                                  const char **CritStr,
+                                  long *CritStrLen)
+{
+       int i;
+       struct UseTable ut;
+       u_char rawdigest[MD5_DIGEST_LEN];
+       struct MD5Context md5context;
+       StrBuf *guid;
+       struct cdbdata *cdbut;
+       char timestamp[64];
+       long tslen;
+       time_t ts = time(NULL);
+       time_t tsday = ts / (8*60*60); /* just care for a day... */
+
+       tslen = snprintf(timestamp, sizeof(timestamp), "%ld", tsday);
+       MD5Init(&md5context);
+
+       for (i = 0; i < nCriterions; i++)
+               MD5Update(&md5context,
+                         (const unsigned char*)CritStr[i], CritStrLen[i]);
+       MD5Update(&md5context,
+                 (const unsigned char*)timestamp, tslen);
+       MD5Final(rawdigest, &md5context);
+
+       guid = NewStrBufPlain(NULL,
+                             MD5_DIGEST_LEN * 2 + 12);
+       StrBufHexEscAppend(guid, NULL, rawdigest, MD5_DIGEST_LEN);
+       StrBufAppendBufPlain(guid, HKEY("_fldpt"), 0);
+       if (StrLength(guid) > 40)
+               StrBufCutAt(guid, 40, NULL);
+       /* Find out if we've already sent a similar message */
+       memcpy(ut.ut_msgid, SKEY(guid));
+       ut.ut_timestamp = ts;
+
+       cdbut = cdb_fetch(CDB_USETABLE, SKEY(guid));
+
+       if (cdbut != NULL) {
+               /* yes, we did. flood protection kicks in. */
+               syslog(LOG_DEBUG,
+                      "not sending message again\n");
+               cdb_free(cdbut);
+       }
+
+       /* rewrite the record anyway, to update the timestamp */
+       cdb_store(CDB_USETABLE,
+                 SKEY(guid),
+                 &ut, sizeof(struct UseTable) );
+
+       if (cdbut != NULL) return;
+       /* no, this message isn't sent recently; go ahead. */
+       quickie_message(from,
+                       fromaddr,
+                       to,
+                       room,
+                       text, 
+                       format_type,
+                       subject);
+}
 
 
 /*
@@ -4013,7 +4104,7 @@ int CtdlCheckInternetMailPermission(struct ctdluser *who) {
        /* User flagged ok? */
        if (who->flags & US_INTERNET) return(2);
 
-       /* Aide level access? */
+       /* Admin level access? */
        if (who->axlevel >= AxAideU) return(3);
 
        /* No mail for you! */
@@ -4896,7 +4987,7 @@ void cmd_move(char *args)
         */
        permit = 0;
 
-       /* Aides can move/copy */
+       /* Admins can move/copy */
        if (CC->user.axlevel >= AxAideU) permit = 1;
 
        /* Room aides can move/copy */