long config_msgnum;
struct addresses_to_be_filed *atbf = NULL;
+/* This temp file holds the queue of operations for AdjRefCount() */
+static FILE *arcfp = NULL;
+
/*
* This really belongs in serv_network.c, but I don't know how to export
* symbols between modules.
char setstr[SIZ], lostr[SIZ], histr[SIZ];
size_t tmp;
+ /* Don't bother doing *anything* if we were passed a list of zero messages */
+ if (num_target_msgnums < 1) {
+ return;
+ }
+
lprintf(CTDL_DEBUG, "CtdlSetSeen(%d msgs starting with %ld, %d, %d)\n",
num_target_msgnums, target_msgnums[0],
target_setting, which_set);
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;
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);
{
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) {
++start_of_text;
start_of_text = strstr(start_of_text, "\n");
++start_of_text;
+
+ char outbuf[1024];
+ int outlen = 0;
+ int nllen = strlen(nl);
while (ch=*mptr, ch!=0) {
if (ch==13) {
/* do nothing */
}
- else switch(headers_only) {
- case HEADERS_NONE:
- if (mptr >= start_of_text) {
- if (ch == 10) cprintf("%s", nl);
- else cprintf("%c", ch);
+ else {
+ if (
+ ((headers_only == HEADERS_NONE) && (mptr >= start_of_text))
+ || ((headers_only == HEADERS_ONLY) && (mptr < start_of_text))
+ || ((headers_only != HEADERS_NONE) && (headers_only != HEADERS_ONLY))
+ ) {
+ if (ch == 10) {
+ sprintf(&outbuf[outlen], "%s", nl);
+ outlen += nllen;
}
- break;
- case HEADERS_ONLY:
- if (mptr < start_of_text) {
- if (ch == 10) cprintf("%s", nl);
- else cprintf("%c", ch);
+ else {
+ outbuf[outlen++] = ch;
}
- break;
- default:
- if (ch == 10) cprintf("%s", nl);
- else cprintf("%c", ch);
- break;
+ }
}
++mptr;
+ if (outlen > 1000) {
+ client_write(outbuf, outlen);
+ outlen = 0;
+ }
+ }
+ if (outlen > 0) {
+ client_write(outbuf, outlen);
+ outlen = 0;
}
+
goto DONE;
}
}
void cmd_msg3(char *cmdbuf)
{
long msgnum;
- struct CtdlMessage *msg;
+ struct CtdlMessage *msg = NULL;
struct ser_ret smr;
if (CC->internal_pgm == 0) {
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, 1, "", 0);
+ CtdlDeleteMessages(CC->room.QRname, &old_msgnum, 1, "");
}
}
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);
}
if (subject != NULL) {
+ long length;
striplt(subject);
- if (strlen(subject) > 0) {
- msg->cm_fields['U'] = strdup(subject);
+ length = strlen(subject);
+ if (length > 0) {
+ long i;
+ long IsAscii;
+ IsAscii = -1;
+ i = 0;
+ while ((subject[i] != '\0') &&
+ (IsAscii = isascii(subject[i]) != 0 ))
+ i++;
+ if (IsAscii != 0)
+ msg->cm_fields['U'] = strdup(subject);
+ else /* ok, we've got utf8 in the string. */
+ {
+ msg->cm_fields['U'] = rfc2047encode(subject, length);
+ }
+
}
}
* returns 0 on success.
*/
int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, size_t n) {
+ int ra;
if (!(CC->logged_in)) {
snprintf(errmsgbuf, n, "Not logged in.");
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);
}
/*
* Validate recipients, count delivery types and errors, and handle aliasing
* FIXME check for dupes!!!!!
- * Returns 0 if all addresses are ok, -1 if no addresses were specified,
- * or the number of addresses found invalid.
+ * Returns 0 if all addresses are ok, ret->num_error = -1 if no addresses
+ * were specified, or the number of addresses found invalid.
+ * caller needs to free the result.
*/
struct recptypes *validate_recipients(char *supplied_recipients) {
struct recptypes *ret;
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 */
- int deferred /* let TDAP sweep it later */
+ char *content_type /* or "" for any */
)
{
int delete_this;
struct MetaData smi;
- lprintf(CTDL_DEBUG, "CtdlDeleteMessages(%s, %d msgs, %s, %d)\n",
- room_name, num_dmsgnums, content_type, deferred);
+ lprintf(CTDL_DEBUG, "CtdlDeleteMessages(%s, %d msgs, %s)\n",
+ room_name, num_dmsgnums, content_type);
/* get room record, obtaining a lock... */
if (lgetroom(&qrbuf, room_name) != 0) {
}
lputroom(&qrbuf);
- /*
- * If the delete operation is "deferred" (and technically, any delete
- * operation not performed by THE DREADED AUTO-PURGER ought to be
- * a deferred delete) then we save a pointer to the message in the
- * 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) ) {
- CtdlCopyMsgsToRoom(dellist, num_deleted, DELETED_MSGS_ROOM);
- }
-
/* 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
* was in, the reference count will reach zero and the message will
msgs[i] = atol(msgtok);
}
- num_deleted = CtdlDeleteMessages(CC->room.QRname, msgs, num_msgs, "", 1);
+ num_deleted = CtdlDeleteMessages(CC->room.QRname, msgs, num_msgs, "");
free(msgs);
if (num_deleted) {
* if this is a 'move' rather than a 'copy' operation.
*/
if (is_copy == 0) {
- CtdlDeleteMessages(CC->room.QRname, msgs, num_msgs, "", 0);
+ CtdlDeleteMessages(CC->room.QRname, msgs, num_msgs, "");
}
free(msgs);
/* Use the negative of the message number for the metadata db index */
TheIndex = (0L - smibuf->meta_msgnum);
- lprintf(CTDL_DEBUG, "PutMetaData(%ld) - ref count is %d\n",
- smibuf->meta_msgnum, smibuf->meta_refcount);
-
cdb_store(CDB_MSGMAIN,
&TheIndex, (int)sizeof(long),
smibuf, (int)sizeof(struct MetaData));
}
/*
- * AdjRefCount - change the reference count for a message;
- * delete the message if it reaches zero
+ * AdjRefCount - submit an adjustment to the reference count for a message.
+ * (These are just queued -- we actually process them later.)
*/
void AdjRefCount(long msgnum, int incr)
+{
+ struct arcq new_arcq;
+
+ begin_critical_section(S_SUPPMSGMAIN);
+ if (arcfp == NULL) {
+ arcfp = fopen(file_arcq, "ab+");
+ }
+ end_critical_section(S_SUPPMSGMAIN);
+
+ /* msgnum < 0 means that we're trying to close the file */
+ if (msgnum < 0) {
+ lprintf(CTDL_DEBUG, "Closing the AdjRefCount queue file\n");
+ begin_critical_section(S_SUPPMSGMAIN);
+ if (arcfp != NULL) {
+ fclose(arcfp);
+ arcfp = NULL;
+ }
+ end_critical_section(S_SUPPMSGMAIN);
+ return;
+ }
+
+ /*
+ * If we can't open the queue, perform the operation synchronously.
+ */
+ if (arcfp == NULL) {
+ TDAP_AdjRefCount(msgnum, incr);
+ return;
+ }
+
+ new_arcq.arcq_msgnum = msgnum;
+ new_arcq.arcq_delta = incr;
+ fwrite(&new_arcq, sizeof(struct arcq), 1, arcfp);
+ fflush(arcfp);
+
+ return;
+}
+
+
+/*
+ * TDAP_ProcessAdjRefCountQueue()
+ *
+ * Process the queue of message count adjustments that was created by calls
+ * to AdjRefCount() ... by reading the queue and calling TDAP_AdjRefCount()
+ * for each one. This should be an "off hours" operation.
+ */
+int TDAP_ProcessAdjRefCountQueue(void)
+{
+ char file_arcq_temp[PATH_MAX];
+ int r;
+ FILE *fp;
+ struct arcq arcq_rec;
+ int num_records_processed = 0;
+
+ snprintf(file_arcq_temp, sizeof file_arcq_temp, "%s2", file_arcq);
+
+ begin_critical_section(S_SUPPMSGMAIN);
+ if (arcfp != NULL) {
+ fclose(arcfp);
+ arcfp = NULL;
+ }
+
+ r = link(file_arcq, file_arcq_temp);
+ if (r != 0) {
+ lprintf(CTDL_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno));
+ end_critical_section(S_SUPPMSGMAIN);
+ return(num_records_processed);
+ }
+
+ unlink(file_arcq);
+ end_critical_section(S_SUPPMSGMAIN);
+
+ fp = fopen(file_arcq_temp, "rb");
+ if (fp == NULL) {
+ lprintf(CTDL_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno));
+ return(num_records_processed);
+ }
+
+ while (fread(&arcq_rec, sizeof(struct arcq), 1, fp) == 1) {
+ TDAP_AdjRefCount(arcq_rec.arcq_msgnum, arcq_rec.arcq_delta);
+ ++num_records_processed;
+ }
+
+ fclose(fp);
+ r = unlink(file_arcq_temp);
+ if (r != 0) {
+ lprintf(CTDL_CRIT, "%s: %s\n", file_arcq_temp, strerror(errno));
+ }
+
+ return(num_records_processed);
+}
+
+
+
+/*
+ * TDAP_AdjRefCount - adjust the reference count for a message.
+ * This one does it "for real" because it's called by
+ * the autopurger function that processes the queue
+ * created by AdjRefCount(). If a message's reference
+ * count becomes zero, we also delete the message from
+ * disk and de-index it.
+ */
+void TDAP_AdjRefCount(long msgnum, int incr)
{
struct MetaData smi;
smi.meta_refcount += incr;
PutMetaData(&smi);
end_critical_section(S_SUPPMSGMAIN);
- lprintf(CTDL_DEBUG, "msg %ld ref count incr %d, is now %d\n",
+ lprintf(CTDL_DEBUG, "msg %ld ref count delta %d, is now %d\n",
msgnum, incr, smi.meta_refcount);
/* If the reference count is now zero, delete the message
delnum = (0L - msgnum);
cdb_delete(CDB_MSGMAIN, &delnum, (int)sizeof(long));
}
+
}
/*
*/
if (is_unique) {
lprintf(CTDL_DEBUG, "Deleted %d other msgs of this type\n",
- CtdlDeleteMessages(roomname, NULL, 0, content_type, 0)
+ CtdlDeleteMessages(roomname, NULL, 0, content_type)
);
}
/* Now write the data */