CtdlOutputMsg(msgid, MT_DOWNLOAD, 0, 1, 1, NULL);
}
-
/*
- * Save a message pointer into a specified room
+ * Save one or more message pointers into a specified room
* (Returns 0 for success, nonzero for failure)
* roomname may be NULL to use the current room
*
* Note that the 'supplied_msg' field may be set to NULL, in which case
* the message will be fetched from disk, by number, if we need to perform
* replication checks. This adds an additional database read, so if the
- * caller already has the message in memory then it should be supplied.
+ * caller already has the message in memory then it should be supplied. (Obviously
+ * this mode of operation only works if we're saving a single message.)
*/
-int CtdlSaveMsgPointerInRoom(char *roomname, long msgid, int do_repl_check,
- struct CtdlMessage *supplied_msg) {
- int i;
+int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newmsgs,
+ int do_repl_check, struct CtdlMessage *supplied_msg)
+{
+ int i, j, unique;
char hold_rm[ROOMNAMELEN];
struct cdbdata *cdbfr;
int num_msgs;
long *msglist;
long highest_msg = 0L;
+
+ long msgid = 0;
struct CtdlMessage *msg = NULL;
- /*lprintf(CTDL_DEBUG,
- "CtdlSaveMsgPointerInRoom(room=%s, msgid=%ld, repl=%d)\n",
- roomname, msgid, do_repl_check);*/
+ long *msgs_to_be_merged = NULL;
+ int num_msgs_to_be_merged = 0;
+
+ lprintf(CTDL_DEBUG,
+ "CtdlSaveMsgPointersInRoom(room=%s, num_msgs=%d, repl=%d)\n",
+ roomname, num_newmsgs, do_repl_check);
strcpy(hold_rm, CC->room.QRname);
+ /* Sanity checks */
+ if (newmsgidlist == NULL) return(ERROR + INTERNAL_ERROR);
+ if (num_newmsgs < 1) return(ERROR + INTERNAL_ERROR);
+ if (num_newmsgs > 1) supplied_msg = NULL;
+
/* Now the regular stuff */
if (lgetroom(&CC->room,
((roomname != NULL) ? roomname : CC->room.QRname) )
return(ERROR + ROOM_NOT_FOUND);
}
+
+ msgs_to_be_merged = malloc(sizeof(long) * num_newmsgs);
+ num_msgs_to_be_merged = 0;
+
+
cdbfr = cdb_fetch(CDB_MSGLISTS, &CC->room.QRnumber, sizeof(long));
if (cdbfr == NULL) {
msglist = NULL;
cdb_free(cdbfr);
}
- /* Make sure the message doesn't already exist in this room. It
- * is absolutely taboo to have more than one reference to the same
- * message in a room.
+
+ /* Create a list of msgid's which were supplied by the caller, but do
+ * not already exist in the target room. It is absolutely taboo to
+ * have more than one reference to the same message in a room.
*/
- if (num_msgs > 0) for (i=0; i<num_msgs; ++i) {
- if (msglist[i] == msgid) {
- lputroom(&CC->room); /* unlock the room */
- getroom(&CC->room, hold_rm);
- free(msglist);
- return(ERROR + ALREADY_EXISTS);
+ for (i=0; i<num_newmsgs; ++i) {
+ unique = 1;
+ if (num_msgs > 0) for (j=0; j<num_msgs; ++j) {
+ if (msglist[j] == newmsgidlist[i]) {
+ unique = 0;
+ }
+ }
+ if (unique) {
+ msgs_to_be_merged[num_msgs_to_be_merged++] = newmsgidlist[i];
}
}
- /* Now add the new message */
- ++num_msgs;
- msglist = realloc(msglist, (num_msgs * sizeof(long)));
+ lprintf(9, "%d unique messages to be merged\n", num_msgs_to_be_merged);
+ /*
+ * Now merge the new messages
+ */
+ msglist = realloc(msglist, (sizeof(long) * (num_msgs + num_msgs_to_be_merged)) );
if (msglist == NULL) {
lprintf(CTDL_ALERT, "ERROR: can't realloc message list!\n");
}
- msglist[num_msgs - 1] = msgid;
+ memcpy(&msglist[num_msgs], msgs_to_be_merged, (sizeof(long) * num_msgs_to_be_merged) );
+ num_msgs += num_msgs_to_be_merged;
/* Sort the message list, so all the msgid's are in order */
num_msgs = sort_msglist(msglist, num_msgs);
/* Perform replication checks if necessary */
if ( (DoesThisRoomNeedEuidIndexing(&CC->room)) && (do_repl_check) ) {
- if (supplied_msg != NULL) {
- msg = supplied_msg;
- }
- else {
- msg = CtdlFetchMessage(msgid, 0);
- }
-
- if (msg != NULL) {
- ReplicationChecks(msg);
- }
+ lprintf(CTDL_DEBUG, "CtdlSaveMsgPointerInRoom() doing repl checks\n");
- }
+ for (i=0; i<num_msgs_to_be_merged; ++i) {
+ msgid = msgs_to_be_merged[i];
+
+ if (supplied_msg != NULL) {
+ msg = supplied_msg;
+ }
+ else {
+ msg = CtdlFetchMessage(msgid, 0);
+ }
+
+ if (msg != NULL) {
+ ReplicationChecks(msg);
+
+ /* If the message has an Exclusive ID, index that... */
+ if (msg->cm_fields['E'] != NULL) {
+ index_message_by_euid(msg->cm_fields['E'], &CC->room, msgid);
+ }
- /* If the message has an Exclusive ID, index that... */
- if (msg != NULL) {
- if (msg->cm_fields['E'] != NULL) {
- index_message_by_euid(msg->cm_fields['E'],
- &CC->room, msgid);
+ /* Free up the memory we may have allocated */
+ if (msg != supplied_msg) {
+ CtdlFreeMessage(msg);
+ }
+ }
+
}
}
- /* Free up the memory we may have allocated */
- if ( (msg != NULL) && (msg != supplied_msg) ) {
- CtdlFreeMessage(msg);
+ else {
+ lprintf(CTDL_DEBUG, "CtdlSaveMsgPointerInRoom() skips repl checks\n");
}
/* Go back to the room we were in before we wandered here... */
getroom(&CC->room, hold_rm);
- /* Bump the reference count for this message. */
- AdjRefCount(msgid, +1);
+ /* Bump the reference count for all messages which were merged */
+ for (i=0; i<num_msgs_to_be_merged; ++i) {
+ AdjRefCount(msgs_to_be_merged[i], +1);
+ }
+
+ /* Free up memory... */
+ if (msgs_to_be_merged != NULL) {
+ free(msgs_to_be_merged);
+ }
/* Return success. */
return (0);
}
+/*
+ * This is the same as CtdlSaveMsgPointersInRoom() but it only accepts
+ * a single message.
+ */
+int CtdlSaveMsgPointerInRoom(char *roomname, long msgid,
+ int do_repl_check, struct CtdlMessage *supplied_msg)
+{
+ return CtdlSaveMsgPointersInRoom(roomname, &msgid, 1, do_repl_check, supplied_msg);
+}
+
+
+
/*
* Message base operation to save a new message to the message store
/* Get a new message number */
newmsgid = get_new_message_number();
- snprintf(msgidbuf, sizeof msgidbuf, "%ld@%s", newmsgid, config.c_fqdn);
+ snprintf(msgidbuf, sizeof msgidbuf, "%010ld@%s", newmsgid, config.c_fqdn);
/* Generate an ID if we don't have one already */
if (msg->cm_fields['I']==NULL) {
old_msgnum = locate_message_by_euid(msg->cm_fields['E'], &CC->room);
if (old_msgnum > 0L) {
lprintf(CTDL_DEBUG, "ReplicationChecks() replacing message %ld\n", old_msgnum);
- CtdlDeleteMessages(CC->room.QRname, old_msgnum, "", 0);
+ CtdlDeleteMessages(CC->room.QRname, &old_msgnum, 1, "", 0);
}
}
* (returns the actual number of messages deleted)
*/
int CtdlDeleteMessages(char *room_name, /* which room */
- long dmsgnum, /* or "0" for any */
+ 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 */
int deferred /* let TDAP sweep it later */
)
long *msglist = NULL;
long *dellist = NULL;
int num_msgs = 0;
- int i;
+ int i, j;
int num_deleted = 0;
int delete_this;
struct MetaData smi;
- lprintf(CTDL_DEBUG, "CtdlDeleteMessages(%s, %ld, %s, %d)\n",
- room_name, dmsgnum, content_type, deferred);
+ lprintf(CTDL_DEBUG, "CtdlDeleteMessages(%s, %d msgs, %s, %d)\n",
+ room_name, num_dmsgnums, content_type, deferred);
/* get room record, obtaining a lock... */
if (lgetroom(&qrbuf, room_name) != 0) {
/* Set/clear a bit for each criterion */
- if ((dmsgnum == 0L) || (msglist[i] == dmsgnum)) {
+ /* 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)) {
delete_this |= 0x01;
}
+ else {
+ for (j=0; j<num_dmsgnums; ++j) {
+ if (msglist[i] == dmsgnums[j]) {
+ delete_this |= 0x01;
+ }
+ }
+ }
+
if (strlen(content_type) == 0) {
delete_this |= 0x02;
} else {
* DELETED_MSGS_ROOM. This will cause the reference count to remain
* at least 1, which will save the user from having to synchronously
* wait for various disk-intensive operations to complete.
+ *
+ * Slick -- we now use the new bulk API for moving messages.
*/
if ( (deferred) && (num_deleted) ) {
- for (i=0; i<num_deleted; ++i) {
- CtdlCopyMsgToRoom(dellist[i], DELETED_MSGS_ROOM);
- }
+ CtdlCopyMsgsToRoom(dellist, num_deleted, DELETED_MSGS_ROOM);
}
/* Go through the messages we pulled out of the index, and decrement
}
delnum = extract_long(delstr, 0);
- num_deleted = CtdlDeleteMessages(CC->room.QRname, delnum, "", 1);
+ num_deleted = CtdlDeleteMessages(CC->room.QRname, &delnum, 1, "", 1);
if (num_deleted) {
cprintf("%d %d message%s deleted.\n", CIT_OK,
/*
- * Back end API function for moves and deletes
+ * Back end API function for moves and deletes (multiple messages)
*/
-int CtdlCopyMsgToRoom(long msgnum, char *dest) {
+int CtdlCopyMsgsToRoom(long *msgnums, int num_msgs, char *dest) {
int err;
- err = CtdlSaveMsgPointerInRoom(dest, msgnum, 1, NULL);
+ err = CtdlSaveMsgPointersInRoom(dest, msgnums, num_msgs, 1, NULL);
if (err != 0) return(err);
return(0);
}
+/*
+ * Back end API function for moves and deletes (single message)
+ */
+int CtdlCopyMsgToRoom(long msgnum, char *dest) {
+ return CtdlCopyMsgsToRoom(&msgnum, 1, dest);
+}
+
+
/*
* move or copy a message to another room
* if this is a 'move' rather than a 'copy' operation.
*/
if (is_copy == 0) {
- CtdlDeleteMessages(CC->room.QRname, num, "", 0);
+ CtdlDeleteMessages(CC->room.QRname, &num, 1, "", 0);
}
cprintf("%d Message %s.\n", CIT_OK, (is_copy ? "copied" : "moved") );
*/
if (is_unique) {
lprintf(CTDL_DEBUG, "Deleted %d other msgs of this type\n",
- CtdlDeleteMessages(roomname, 0L, content_type, 0)
+ CtdlDeleteMessages(roomname, NULL, 0, content_type, 0)
);
}
/* Now write the data */