Merge branch 'master' of ssh://git.citadel.org/appl/gitroot/citadel
[citadel.git] / citadel / msgbase.c
index 8834be2fe27f163c658128ce08176b6ac4000eef..f23af01c8d43302e9c8b2f8ec00c1c3f4e5287c2 100644 (file)
@@ -68,6 +68,8 @@ struct addresses_to_be_filed *atbf = NULL;
 /* This temp file holds the queue of operations for AdjRefCount() */
 static FILE *arcfp = NULL;
 
+void AdjRefCountList(long *msgnum, long nmsg, int incr);
+
 /*
  * These are the four-character field headers we use when outputting
  * messages in Citadel format (as opposed to RFC822 format).
@@ -614,9 +616,23 @@ int CtdlForEachMessage(int mode, long ref, char *search_string,
        }
 
        /* Learn about the user and room in question */
+       if (server_shutting_down) {
+               if (need_to_free_re) regfree(&re);
+               return -1;
+       }
        CtdlGetUser(&CC->user, CC->curr_user);
+
+       if (server_shutting_down) {
+               if (need_to_free_re) regfree(&re);
+               return -1;
+       }
        CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
 
+       if (server_shutting_down) {
+               if (need_to_free_re) regfree(&re);
+               return -1;
+       }
+
        /* Load the message list */
        cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long));
        if (cdbfr == NULL) {
@@ -649,6 +665,11 @@ int CtdlForEachMessage(int mode, long ref, char *search_string,
                         * enough to only do the read if the caller has
                         * specified something that will need it.
                         */
+                       if (server_shutting_down) {
+                               if (need_to_free_re) regfree(&re);
+                               free(msglist);
+                               return -1;
+                       }
                        GetMetaData(&smi, msglist[a]);
 
                        /* if (strcasecmp(smi.meta_content_type, content_type)) { old non-regex way */
@@ -666,6 +687,11 @@ int CtdlForEachMessage(int mode, long ref, char *search_string,
        if (num_msgs > 0) {
                if (compare != NULL) {
                        for (a = 0; a < num_msgs; ++a) {
+                               if (server_shutting_down) {
+                                       if (need_to_free_re) regfree(&re);
+                                       free(msglist);
+                                       return -1;
+                               }
                                msg = CtdlFetchMessage(msglist[a], 1);
                                if (msg != NULL) {
                                        if (CtdlMsgCmp(msg, compare)) {
@@ -728,6 +754,11 @@ int CtdlForEachMessage(int mode, long ref, char *search_string,
         */
        if (num_msgs > 0)
                for (a = 0; a < num_msgs; ++a) {
+                       if (server_shutting_down) {
+                               if (need_to_free_re) regfree(&re);
+                               free(msglist);
+                               return num_processed;
+                       }
                        thismsg = msglist[a];
                        if (mode == MSGS_ALL) {
                                is_seen = 0;
@@ -2763,9 +2794,7 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms
 
        /* Bump the reference count for all messages which were merged */
        if (!suppress_refcount_adj) {
-               for (i=0; i<num_msgs_to_be_merged; ++i) {
-                       AdjRefCount(msgs_to_be_merged[i], +1);
-               }
+               AdjRefCountList(msgs_to_be_merged, num_msgs_to_be_merged, +1);
        }
 
        /* Free up memory... */
@@ -4283,6 +4312,7 @@ void free_recipients(struct recptypes *valid) {
        if (valid->display_recp != NULL)        free(valid->display_recp);
        if (valid->bounce_to != NULL)           free(valid->bounce_to);
        if (valid->envelope_from != NULL)       free(valid->envelope_from);
+       if (valid->sending_room != NULL)        free(valid->sending_room);
        free(valid);
 }
 
@@ -4670,32 +4700,51 @@ int CtdlDeleteMessages(char *room_name,         /* which room */
                cdb_free(cdbfr);
        }
        if (num_msgs > 0) {
-               for (i = 0; i < num_msgs; ++i) {
+               int have_contenttype = !IsEmptyStr(content_type);
+               int have_delmsgs = (num_dmsgnums == 0) || (dmsgnums == NULL);
+               int have_more_del = 1;
+
+               num_msgs = sort_msglist(msglist, num_msgs);
+               if (num_dmsgnums > 1)
+                       num_dmsgnums = sort_msglist(dmsgnums, num_dmsgnums);
+/*
+               {
+                       StrBuf *dbg = NewStrBuf();
+                       for (i = 0; i < num_dmsgnums; i++)
+                               StrBufAppendPrintf(dbg, ", %ld", dmsgnums[i]);
+                       syslog(LOG_DEBUG, "Deleting before: %s", ChrPtr(dbg));
+                       FreeStrBuf(&dbg);
+               }
+*/
+               i = 0; j = 0;
+               while ((i < num_msgs) && (have_more_del)) {
                        delete_this = 0x00;
 
+
                        /* Set/clear a bit for each criterion */
 
                        /* 0 messages in the list or a null list means that we are
                         * interested in deleting any messages which meet the other criteria.
                         */
-                       if ((num_dmsgnums == 0) || (dmsgnums == NULL)) {
+                       if (have_delmsgs) {
                                delete_this |= 0x01;
                        }
                        else {
-                               for (j=0; j<num_dmsgnums; ++j) {
-                                       if (msglist[i] == dmsgnums[j]) {
-                                               delete_this |= 0x01;
-                                       }
+                               while ((i < num_msgs) && (msglist[i] < dmsgnums[j])) i++;
+                               if (msglist[i] == dmsgnums[j]) {
+                                       delete_this |= 0x01;
                                }
+                               j++;
+                               have_more_del = (j < num_dmsgnums);
                        }
 
-                       if (IsEmptyStr(content_type)) {
-                               delete_this |= 0x02;
-                       } else {
+                       if (have_contenttype) {
                                GetMetaData(&smi, msglist[i]);
                                if (regexec(&re, smi.meta_content_type, 1, &pm, 0) == 0) {
                                        delete_this |= 0x02;
                                }
+                       } else {
+                               delete_this |= 0x02;
                        }
 
                        /* Delete message only if all bits are set */
@@ -4703,8 +4752,17 @@ int CtdlDeleteMessages(char *room_name,          /* which room */
                                dellist[num_deleted++] = msglist[i];
                                msglist[i] = 0L;
                        }
+                       i++;
                }
-
+/*
+               {
+                       StrBuf *dbg = NewStrBuf();
+                       for (i = 0; i < num_deleted; i++)
+                               StrBufAppendPrintf(dbg, ", %ld", dellist[i]);
+                       syslog(LOG_DEBUG, "Deleting: %s", ChrPtr(dbg));
+                       FreeStrBuf(&dbg);
+               }
+*/
                num_msgs = sort_msglist(msglist, num_msgs);
                cdb_store(CDB_MSGLISTS, &qrbuf.QRnumber, (int)sizeof(long),
                          msglist, (int)(num_msgs * sizeof(long)));
@@ -4724,11 +4782,12 @@ int CtdlDeleteMessages(char *room_name,         /* which room */
         * and we don't want that happening during an S_ROOMS critical
         * section.
         */
-       if (num_deleted) for (i=0; i<num_deleted; ++i) {
+       if (num_deleted) {
+               for (i=0; i<num_deleted; ++i) {
                        PerformDeleteHooks(qrbuf.QRname, dellist[i]);
-                       AdjRefCount(dellist[i], -1);
                }
-
+               AdjRefCountList(dellist, num_deleted, -1);
+       }
        /* Now free the memory we used, and go away. */
        if (msglist != NULL) free(msglist);
        if (dellist != NULL) free(dellist);
@@ -5009,6 +5068,57 @@ void AdjRefCount(long msgnum, int incr)
        return;
 }
 
+void AdjRefCountList(long *msgnum, long nmsg, int incr)
+{
+       long i, the_size, offset;
+       struct arcq *new_arcq;
+       int rv = 0;
+
+       syslog(LOG_DEBUG, "AdjRefCountList() msg %ld ref count delta %+d\n", nmsg, incr);
+
+       begin_critical_section(S_SUPPMSGMAIN);
+       if (arcfp == NULL) {
+               arcfp = fopen(file_arcq, "ab+");
+               chown(file_arcq, CTDLUID, (-1));
+               chmod(file_arcq, 0600);
+       }
+       end_critical_section(S_SUPPMSGMAIN);
+
+       /*
+        * If we can't open the queue, perform the operation synchronously.
+        */
+       if (arcfp == NULL) {
+               for (i = 0; i < nmsg; i++)
+                       TDAP_AdjRefCount(msgnum[i], incr);
+               return;
+       }
+
+       the_size = sizeof(struct arcq) * nmsg;
+       new_arcq = malloc(the_size);
+       for (i = 0; i < nmsg; i++) {
+               new_arcq[i].arcq_msgnum = msgnum[i];
+               new_arcq[i].arcq_delta = incr;
+       }
+       rv = 0;
+       offset = 0;
+       while ((rv >= 0) && (offset < the_size))
+       {
+               rv = fwrite(new_arcq + offset, 1, the_size - offset, arcfp);
+               if (rv == -1) {
+                       syslog(LOG_EMERG, "Couldn't write Refcount Queue File %s: %s\n",
+                              file_arcq,
+                              strerror(errno));
+               }
+               else {
+                       offset += rv;
+               }
+       }
+       free(new_arcq);
+       fflush(arcfp);
+
+       return;
+}
+
 
 /*
  * TDAP_ProcessAdjRefCountQueue()