-/* $Cambridge: exim/src/src/queue.c,v 1.10 2006/02/14 15:24:10 ph10 Exp $ */
-
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2006 */
+/* Copyright (c) University of Cambridge 1995 - 2015 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions that operate on the input queue. */
+/* Routines with knowlege of spool layout */
+
+static void
+spool_pname_buf(uschar * buf, int len)
+{
+snprintf(CS buf, len, "%s/%s/input", spool_directory, queue_name);
+}
+
+static uschar *
+spool_dname(const uschar * purpose, uschar * subdir)
+{
+return string_sprintf("%s/%s/%s/%s",
+ spool_directory, queue_name, purpose, subdir);
+}
+
+uschar *
+spool_sname(const uschar * purpose, uschar * subdir)
+{
+return string_sprintf("%s%s%s%s%s",
+ queue_name, *queue_name ? "/" : "",
+ purpose,
+ *subdir ? "/" : "", subdir);
+}
+
+uschar *
+spool_fname(const uschar * purpose, uschar * subdir, uschar * fname, uschar * suffix)
+{
+return string_sprintf("%s/%s/%s/%s/%s%s",
+ spool_directory, queue_name, purpose, subdir, fname, suffix);
+}
+
+
+
+
+#ifndef COMPILE_UTILITY
+
/* The number of nodes to use for the bottom-up merge sort when a list of queue
items is to be ordered. The code for this sort was contributed as a patch by
Michael Haardt. */
/* Set up prototype for the directory name. */
-sprintf(CS buffer, "%s/input", spool_directory);
+spool_pname_buf(buffer, sizeof(buffer));
+buffer[sizeof(buffer) - 3] = 0;
subptr = Ustrlen(buffer);
buffer[subptr+2] = 0; /* terminator for lengthened name */
buffer[subptr+1] = subdirchar;
}
- dd = opendir(CS buffer);
- if (dd == NULL) continue;
+ DEBUG(D_queue_run) debug_printf("looking in %s\n", buffer);
+ if (!(dd = opendir(CS buffer)))
+ continue;
/* Now scan the directory. */
{
if (!split_spool_directory && count <= 2)
{
+ uschar subdir[2];
+
rmdir(CS buffer);
- sprintf(CS big_buffer, "%s/msglog/%c", spool_directory, subdirchar);
- rmdir(CS big_buffer);
+ subdir[0] = subdirchar; subdir[1] = 0;
+ rmdir(CS spool_dname(US"msglog", subdir));
}
if (subdiroffset > 0) break; /* Single sub-directory */
}
}
log_detail = string_copy(big_buffer);
- log_write(L_queue_run, LOG_MAIN, "Start queue run: %s", log_detail);
+ if (*queue_name)
+ log_write(L_queue_run, LOG_MAIN, "Start '%s' queue run: %s",
+ queue_name, log_detail);
+ else
+ log_write(L_queue_run, LOG_MAIN, "Start queue run: %s", log_detail);
}
/* If deliver_selectstring is a regex, compile it. */
/* Check that the message still exists */
message_subdir[0] = f->dir_uschar;
- sprintf(CS buffer, "%s/input/%s/%s", spool_directory, message_subdir,
- f->text);
- if (Ustat(buffer, &statbuf) < 0) continue;
+ if (Ustat(spool_fname(US"input", message_subdir, f->text, US""), &statbuf) < 0)
+ continue;
/* There are some tests that require the reading of the header file. Ensure
the store used is scavenged afterwards so that this process doesn't keep
the mere fact that read() unblocks is enough. */
set_process_info("running queue: waiting for children of %d", pid);
- (void)read(pfd[pipe_read], buffer, sizeof(buffer));
+ if (read(pfd[pipe_read], buffer, sizeof(buffer)) > 0)
+ log_write(0, LOG_MAIN|LOG_PANIC, "queue run: unexpected data on pipe");
(void)close(pfd[pipe_read]);
set_process_info("running queue");
/* At top level, log the end of the run. */
-if (!recurse) log_write(L_queue_run, LOG_MAIN, "End queue run: %s", log_detail);
+if (!recurse)
+ if (*queue_name)
+ log_write(L_queue_run, LOG_MAIN, "End '%s' queue run: %s",
+ queue_name, log_detail);
+ else
+ log_write(L_queue_run, LOG_MAIN, "End queue run: %s", log_detail);
}
int ptr;
FILE *jread;
struct stat statbuf;
+ uschar * fname = spool_fname(US"input", message_subdir, f->text, US"");
- sprintf(CS big_buffer, "%s/input/%s/%s", spool_directory, message_subdir,
- f->text);
- ptr = Ustrlen(big_buffer)-1;
- big_buffer[ptr] = 'D';
+ ptr = Ustrlen(fname)-1;
+ fname[ptr] = 'D';
/* Add the data size to the header size; don't count the file name
at the start of the data file, but add one for the notional blank line
that precedes the data. */
- if (Ustat(big_buffer, &statbuf) == 0)
+ if (Ustat(fname, &statbuf) == 0)
size = message_size + statbuf.st_size - SPOOL_DATA_START_OFFSET + 1;
i = (now - received_time)/60; /* minutes on queue */
if (i > 90)
/* Collect delivered addresses from any J file */
- big_buffer[ptr] = 'J';
- jread = Ufopen(big_buffer, "rb");
+ fname[ptr] = 'J';
+ jread = Ufopen(fname, "rb");
if (jread != NULL)
{
while (Ufgets(big_buffer, big_buffer_size, jread) != NULL)
if (save_errno == ERRNO_SPOOLFORMAT)
{
struct stat statbuf;
- sprintf(CS big_buffer, "%s/input/%s/%s", spool_directory, message_subdir,
- f->text);
- if (Ustat(big_buffer, &statbuf) == 0)
+ uschar * fname = spool_fname(US"input", message_subdir, f->text, US"");
+
+ if (Ustat(fname, &statbuf) == 0)
printf("*** spool format error: size=" OFF_T_FMT " ***",
statbuf.st_size);
else printf("*** spool format error ***");
* Act on a specific message *
*************************************************/
-/* Actions that require a list of addresses make use of
-argv/argc/recipients_arg. Other actions do not. This function does its
-own authority checking.
+/* Actions that require a list of addresses make use of argv/argc/
+recipients_arg. Other actions do not. This function does its own
+authority checking.
Arguments:
id id of the message to work on
uschar *doing = NULL;
uschar *username;
uschar *errmsg;
-uschar spoolname[256];
+uschar spoolname[32];
/* Set the global message_id variable, used when re-writing spool files. This
also causes message ids to be added to log messages. */
for (i = 0; i < 2; i++)
{
- message_subdir[0] = (split_spool_directory == (i == 0))? id[5] : 0;
- sprintf(CS spoolname, "%s/%s/%s/%s%s", spool_directory, subdirectory,
- message_subdir, id, suffix);
- fd = Uopen(spoolname, O_RDONLY, 0);
- if (fd >= 0) break;
- if (i == 0) continue;
+ message_subdir[0] = split_spool_directory == (i == 0) ? id[5] : 0;
+ if ((fd = Uopen(spool_fname(subdirectory, message_subdir, id, suffix),
+ O_RDONLY, 0)) >= 0)
+ break;
+ if (i == 0)
+ continue;
+
printf("Failed to open %s file for %s%s: %s\n", subdirectory, id, suffix,
strerror(errno));
if (action == MSG_SHOW_LOG && !message_logs)
}
while((rc = read(fd, big_buffer, big_buffer_size)) > 0)
- (void)write(fileno(stdout), big_buffer, rc);
+ rc = write(fileno(stdout), big_buffer, rc);
(void)close(fd);
return TRUE;
only if the action is remove and the user is an admin user, to allow for
tidying up broken states. */
-if (!spool_open_datafile(id))
- {
+if ((deliver_datafile = spool_open_datafile(id)) < 0)
if (errno == ENOENT)
{
yield = FALSE;
strerror(errno));
return FALSE;
}
- }
/* Read the spool header file for the message. Again, continue after an
error only in the case of deleting by an administrator. Setting the third
/* Take the necessary action. */
-printf("Message %s ", id);
+if (action != MSG_SHOW_COPY) printf("Message %s ", id);
switch(action)
{
+ case MSG_SHOW_COPY:
+ deliver_in_buffer = store_malloc(DELIVER_IN_BUFFER_SIZE);
+ deliver_out_buffer = store_malloc(DELIVER_OUT_BUFFER_SIZE);
+ transport_write_message(1, NULL, 0);
+ break;
+
+
case MSG_FREEZE:
if (deliver_freeze)
{
operation, just run everything twice. */
case MSG_REMOVE:
- message_subdir[0] = id[5];
- for (j = 0; j < 2; message_subdir[0] = 0, j++)
{
- sprintf(CS spoolname, "%s/msglog/%s/%s", spool_directory, message_subdir, id);
- if (Uunlink(spoolname) < 0)
- {
- if (errno != ENOENT)
- {
- yield = FALSE;
- printf("Error while removing %s: %s\n", spoolname,
- strerror(errno));
- }
- }
- else removed = TRUE;
+ uschar suffix[3];
+
+ suffix[0] = '-';
+ suffix[2] = 0;
+ message_subdir[0] = id[5];
- for (i = 0; i < 3; i++)
+ for (j = 0; j < 2; message_subdir[0] = 0, j++)
{
- sprintf(CS spoolname, "%s/input/%s/%s-%c", spool_directory, message_subdir,
- id, "DHJ"[i]);
- if (Uunlink(spoolname) < 0)
- {
- if (errno != ENOENT)
- {
- yield = FALSE;
- printf("Error while removing %s: %s\n", spoolname,
- strerror(errno));
- }
- }
- else removed = TRUE;
+ uschar * fname = spool_fname(US"msglog", message_subdir, id, US"");
+
+ DEBUG(D_any) debug_printf(" removing %s", fname);
+ if (Uunlink(fname) < 0)
+ {
+ if (errno != ENOENT)
+ {
+ yield = FALSE;
+ printf("Error while removing %s: %s\n", fname, strerror(errno));
+ }
+ else DEBUG(D_any) debug_printf(" (no file)\n");
+ }
+ else
+ {
+ removed = TRUE;
+ DEBUG(D_any) debug_printf(" (ok)\n");
+ }
+
+ for (i = 0; i < 3; i++)
+ {
+ uschar * fname;
+
+ suffix[1] = (US"DHJ")[i];
+ fname = spool_fname(US"input", message_subdir, id, suffix);
+
+ DEBUG(D_any) debug_printf(" removing %s", fname);
+ if (Uunlink(fname) < 0)
+ {
+ if (errno != ENOENT)
+ {
+ yield = FALSE;
+ printf("Error while removing %s: %s\n", fname, strerror(errno));
+ }
+ else DEBUG(D_any) debug_printf(" (no file)\n");
+ }
+ else
+ {
+ removed = TRUE;
+ DEBUG(D_any) debug_printf(" (done)\n");
+ }
+ }
}
- }
- /* In the common case, the datafile is open (and locked), so give the
- obvious message. Otherwise be more specific. */
+ /* In the common case, the datafile is open (and locked), so give the
+ obvious message. Otherwise be more specific. */
- if (deliver_datafile >= 0) printf("has been removed\n");
- else printf("has been removed or did not exist\n");
- if (removed)
- {
- log_write(0, LOG_MAIN, "removed by %s", username);
- log_write(0, LOG_MAIN, "Completed");
+ if (deliver_datafile >= 0) printf("has been removed\n");
+ else printf("has been removed or did not exist\n");
+ if (removed)
+ {
+ log_write(0, LOG_MAIN, "removed by %s", username);
+ log_write(0, LOG_MAIN, "Completed");
+ }
+ break;
}
- break;
case MSG_MARK_ALL_DELIVERED:
{
if (action == MSG_ADD_RECIPIENT)
{
+#ifdef SUPPORT_I18N
+ if (string_is_utf8(recipient)) allow_utf8_domains = message_smtputf8 = TRUE;
+#endif
receive_add_recipient(recipient, -1);
log_write(0, LOG_MAIN, "recipient <%s> added by %s",
recipient, username);
}
else /* MSG_EDIT_SENDER */
{
+#ifdef SUPPORT_I18N
+ if (string_is_utf8(recipient)) allow_utf8_domains = message_smtputf8 = TRUE;
+#endif
sender_address = recipient;
log_write(0, LOG_MAIN, "sender address changed to <%s> by %s",
recipient, username);
}
if (yield)
- {
if (spool_write_header(id, SW_MODIFYING, &errmsg) >= 0)
printf("has been modified\n");
else
yield = FALSE;
printf("- while %s: %s\n", doing, errmsg);
}
- }
break;
}
/* Closing the datafile releases the lock and permits other processes
to operate on the message (if it still exists). */
-(void)close(deliver_datafile);
-deliver_datafile = -1;
+if (deliver_datafile >= 0)
+ {
+ (void)close(deliver_datafile);
+ deliver_datafile = -1;
+ }
return yield;
}
BOOL *set;
int sep = 0;
struct stat statbuf;
-uschar *s, *ss, *name;
+const uschar *s;
+uschar *ss, *name;
uschar buffer[1024];
if (queue_only_file == NULL) return;
}
}
+#endif /*!COMPILE_UTILITY*/
+
/* End of queue.c */