Use project-standard memory management rather than alloca()
[exim.git] / src / exim_monitor / em_menu.c
index ead5923a8f9f1ffbd8c64106fc092afbfb2dc590..926dbd95b75df8e21fcf644482284dd1413deea6 100644 (file)
@@ -1,11 +1,11 @@
-/* $Cambridge: exim/src/exim_monitor/em_menu.c,v 1.1 2004/10/07 10:39:01 ph10 Exp $ */
-
 /*************************************************
 *                  Exim Monitor                  *
 *************************************************/
 
 /*************************************************
 *                  Exim Monitor                  *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2004 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2021 */
 /* See the file NOTICE for conditions of use and distribution. */
 /* See the file NOTICE for conditions of use and distribution. */
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 
 
 #include "em_hdr.h"
 
 
 #include "em_hdr.h"
@@ -117,10 +117,9 @@ static Arg item_99_arg[] = {
 *        Destroy the menu when popped down       *
 *************************************************/
 
 *        Destroy the menu when popped down       *
 *************************************************/
 
-static void popdownAction(Widget w, XtPointer client_data, XtPointer call_data)
+static void
+popdownAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 {
-client_data = client_data;    /* Keep picky compilers happy */
-call_data = call_data;
 if (highlighted_x >= 0)
   XawTextSinkDisplayText(queue_text_sink,
     highlighted_x, highlighted_y,
 if (highlighted_x >= 0)
   XawTextSinkDisplayText(queue_text_sink,
     highlighted_x, highlighted_y,
@@ -135,32 +134,29 @@ menu_is_up = FALSE;
 *          Display the message log               *
 *************************************************/
 
 *          Display the message log               *
 *************************************************/
 
-static void msglogAction(Widget w, XtPointer client_data, XtPointer call_data)
+static void
+msglogAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 {
-int i;
-uschar buffer[256];
-Widget text = text_create((uschar *)client_data, text_depth);
-FILE *f = NULL;
-
-w = w;      /* Keep picky compilers happy */
-call_data = call_data;
+Widget text = text_create(US client_data, text_depth);
+uschar * fname = NULL;
+FILE * f = NULL;
 
 /* End up with the split version, so message looks right when non-exist */
 
 
 /* End up with the split version, so message looks right when non-exist */
 
-for (i = 0; i < (spool_is_split? 2:1); i++)
+for (int i = 0; i < (spool_is_split ? 2:1); i++)
   {
   {
-  message_subdir[0] = (i != 0)? ((uschar *)client_data)[5] : 0;
-  sprintf(CS buffer, "%s/msglog/%s/%s", spool_directory, message_subdir,
-    (uschar *)client_data);
-  f = fopen(CS buffer, "r");
-  if (f != NULL) break;
+  message_subdir[0] = i != 0 ? (US client_data)[5] : 0;
+  fname = spool_fname(US"msglog", message_subdir, US client_data, US"");
+  if ((f = fopen(CS fname, "r")))
+    break;
   }
 
   }
 
-if (f == NULL)
-  text_showf(text, "%s: %s\n", buffer, strerror(errno));
+if (!f)
+  text_showf(text, "%s: %s\n", fname, strerror(errno));
 else
   {
 else
   {
-  while (Ufgets(buffer, 256, f) != NULL) text_show(text, buffer);
+  uschar buffer[256];
+  while (Ufgets(buffer, sizeof(buffer), f) != NULL) text_show(text, buffer);
   fclose(f);
   }
 }
   fclose(f);
   }
 }
@@ -171,31 +167,29 @@ else
 *          Display the message body               *
 *************************************************/
 
 *          Display the message body               *
 *************************************************/
 
-static void bodyAction(Widget w, XtPointer client_data, XtPointer call_data)
+static void
+bodyAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 {
-int i;
-uschar buffer[256];
-Widget text = text_create((uschar *)client_data, text_depth);
+Widget text = text_create(US client_data, text_depth);
 FILE *f = NULL;
 
 FILE *f = NULL;
 
-w = w;      /* Keep picky compilers happy */
-call_data = call_data;
-
-for (i = 0; i < (spool_is_split? 2:1); i++)
+for (int i = 0; i < (spool_is_split? 2:1); i++)
   {
   {
-  message_subdir[0] = (i != 0)? ((uschar *)client_data)[5] : 0;
-  sprintf(CS buffer, "%s/input/%s/%s-D", spool_directory, message_subdir,
-    (uschar *)client_data);
-  f = fopen(CS buffer, "r");
-  if (f != NULL) break;
+  uschar * fname;
+  message_subdir[0] = i != 0 ? (US client_data)[5] : 0;
+  fname = spool_fname(US"input", message_subdir, US client_data, US"-D");
+  if ((f = fopen(CS fname, "r")))
+    break;
   }
 
   }
 
-if (f == NULL)
+if (!f)
   text_showf(text, "Failed to open file: %s\n", strerror(errno));
 else
   {
   text_showf(text, "Failed to open file: %s\n", strerror(errno));
 else
   {
+  uschar buffer[256];
   int count = 0;
   int count = 0;
-  while (Ufgets(buffer, 256, f) != NULL)
+
+  while (Ufgets(buffer, sizeof(buffer), f) != NULL)
     {
     text_show(text, buffer);
     count += Ustrlen(buffer);
     {
     text_show(text, buffer);
     count += Ustrlen(buffer);
@@ -220,7 +214,8 @@ unless action_output is set. We can't, however, tell until we have run
 the command whether we want the output or not, so the pipe has to be set up in
 all cases. */
 
 the command whether we want the output or not, so the pipe has to be set up in
 all cases. */
 
-static void ActOnMessage(uschar *id, uschar *action, uschar *address_arg)
+static void
+ActOnMessage(uschar *id, uschar *action, uschar *address_arg)
 {
 int pid;
 int pipe_fd[2];
 {
 int pid;
 int pipe_fd[2];
@@ -275,8 +270,12 @@ if (pipe(pipe_fd) != 0)
   return;
   }
 
   return;
   }
 
-fcntl(pipe_fd[0], F_SETFL, O_NONBLOCK);
-fcntl(pipe_fd[1], F_SETFL, O_NONBLOCK);
+if (  fcntl(pipe_fd[0], F_SETFL, O_NONBLOCK)
+   || fcntl(pipe_fd[1], F_SETFL, O_NONBLOCK))
+  {
+  perror("set nonblocking on pipe");
+  exit(1);
+  }
 
 /* Delivering a message can take some time, and we want to show the
 output as it goes along. This requires subprocesses and is coded below. For
 
 /* Delivering a message can take some time, and we want to show the
 output as it goes along. This requires subprocesses and is coded below. For
@@ -329,9 +328,9 @@ if (!delivery)
   if (rc == 0 && Ustrcmp(action + Ustrlen(action) - 4, "-Mes") == 0)
     {
     queue_item *q = find_queue(id, queue_noop, 0);
   if (rc == 0 && Ustrcmp(action + Ustrlen(action) - 4, "-Mes") == 0)
     {
     queue_item *q = find_queue(id, queue_noop, 0);
-    if (q != NULL)
+    if (q)
       {
       {
-      if (q->sender != NULL) store_free(q->sender);
+      if (q->sender) store_free(q->sender);
       q->sender = store_malloc(Ustrlen(address_arg) + 1);
       Ustrcpy(q->sender, address_arg);
       }
       q->sender = store_malloc(Ustrlen(address_arg) + 1);
       Ustrcpy(q->sender, address_arg);
       }
@@ -375,7 +374,7 @@ if ((pid = fork()) == 0)
 
 /* Main process - set up an item for the main ticker to watch. */
 
 
 /* Main process - set up an item for the main ticker to watch. */
 
-if (pid < 0) text_showf(text, "Failed to fork: %s\n", strerror(pid)); else
+if (pid < 0) text_showf(text, "Failed to fork: %s\n", strerror(errno)); else
   {
   pipe_item *p = (pipe_item *)store_malloc(sizeof(pipe_item));
 
   {
   pipe_item *p = (pipe_item *)store_malloc(sizeof(pipe_item));
 
@@ -402,41 +401,32 @@ if (pid < 0) text_showf(text, "Failed to fork: %s\n", strerror(pid)); else
 *        Cause a message to be delivered         *
 *************************************************/
 
 *        Cause a message to be delivered         *
 *************************************************/
 
-static void deliverAction(Widget w, XtPointer client_data, XtPointer call_data)
+static void
+deliverAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 {
-w = w;      /* Keep picky compilers happy */
-call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-v -M", US"");
+ActOnMessage(US client_data, US"-v -M", US"");
 }
 
 }
 
-
-
 /*************************************************
 *        Cause a message to be Frozen            *
 *************************************************/
 
 /*************************************************
 *        Cause a message to be Frozen            *
 *************************************************/
 
-static void freezeAction(Widget w, XtPointer client_data, XtPointer call_data)
+static void
+freezeAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 {
-w = w;      /* Keep picky compilers happy */
-call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-Mf", US"");
+ActOnMessage(US client_data, US"-Mf", US"");
 }
 
 }
 
-
-
 /*************************************************
 *        Cause a message to be thawed            *
 *************************************************/
 
 /*************************************************
 *        Cause a message to be thawed            *
 *************************************************/
 
-static void thawAction(Widget w, XtPointer client_data, XtPointer call_data)
+static void
+thawAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 {
-w = w;      /* Keep picky compilers happy */
-call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-Mt", US"");
+ActOnMessage(US client_data, US"-Mt", US"");
 }
 
 }
 
-
-
 /*************************************************
 *          Take action using dialog data         *
 *************************************************/
 /*************************************************
 *          Take action using dialog data         *
 *************************************************/
@@ -445,25 +435,19 @@ ActOnMessage((uschar *)client_data, US"-Mt", US"");
 in. It is global because it is set up in the action table at
 start-up time. If the string is empty, do nothing. */
 
 in. It is global because it is set up in the action table at
 start-up time. If the string is empty, do nothing. */
 
-XtActionProc dialogAction(Widget w, XEvent *event, String *ss, Cardinal *c)
+XtActionProc
+dialogAction(Widget w, XEvent *event, String *ss, Cardinal *c)
 {
 uschar *s = US XawDialogGetValueString(dialog_widget);
 
 {
 uschar *s = US XawDialogGetValueString(dialog_widget);
 
-w = w;      /* Keep picky compilers happy */
-event = event;
-ss = ss;
-c = c;
-
 XtPopdown((Widget)dialog_shell);
 XtDestroyWidget((Widget)dialog_shell);
 while (isspace(*s)) s++;
 if (s[0] != 0)
 XtPopdown((Widget)dialog_shell);
 XtDestroyWidget((Widget)dialog_shell);
 while (isspace(*s)) s++;
 if (s[0] != 0)
-  {
   if (actioned_message[0] != 0)
     ActOnMessage(actioned_message, action_required, s);
   else
     NonMessageDialogue(s);    /* When called from somewhere else */
   if (actioned_message[0] != 0)
     ActOnMessage(actioned_message, action_required, s);
   else
     NonMessageDialogue(s);    /* When called from somewhere else */
-  }
 return NULL;
 }
 
 return NULL;
 }
 
@@ -477,7 +461,8 @@ return NULL;
 be done to the application until the box is filled in. This
 function is also used by the Hide button handler. */
 
 be done to the application until the box is filled in. This
 function is also used by the Hide button handler. */
 
-void create_dialog(uschar *label, uschar *value)
+void
+create_dialog(uschar *label, uschar *value)
 {
 Arg warg[4];
 Dimension x, y, xx, yy;
 {
 Arg warg[4];
 Dimension x, y, xx, yy;
@@ -539,9 +524,6 @@ XFlush(X_display);
 }
 
 
 }
 
 
-
-
-
 /*************************************************
 *        Cause a recipient to be added           *
 *************************************************/
 /*************************************************
 *        Cause a recipient to be added           *
 *************************************************/
@@ -549,111 +531,96 @@ XFlush(X_display);
 /* This just sets up the dialog box; the action happens when it has been filled
 in. */
 
 /* This just sets up the dialog box; the action happens when it has been filled
 in. */
 
-static void addrecipAction(Widget w, XtPointer client_data, XtPointer call_data)
+static void
+addrecipAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 {
-w = w;      /* Keep picky compilers happy */
-call_data = call_data;
-Ustrcpy(actioned_message, (uschar *)client_data);
+Ustrncpy(actioned_message, client_data, 24);
+actioned_message[23] = '\0';
 action_required = US"-Mar";
 dialog_ref_widget = menushell;
 create_dialog(US"Recipient address to add?", US"");
 }
 
 action_required = US"-Mar";
 dialog_ref_widget = menushell;
 create_dialog(US"Recipient address to add?", US"");
 }
 
-
-
 /*************************************************
 *    Cause an address to be marked delivered     *
 *************************************************/
 
 /*************************************************
 *    Cause an address to be marked delivered     *
 *************************************************/
 
-static void markdelAction(Widget w, XtPointer client_data, XtPointer call_data)
+static void
+markdelAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 {
-w = w;      /* Keep picky compilers happy */
-call_data = call_data;
-Ustrcpy(actioned_message, (uschar *)client_data);
+Ustrncpy(actioned_message, client_data, 24);
+actioned_message[23] = '\0';
 action_required = US"-Mmd";
 dialog_ref_widget = menushell;
 create_dialog(US"Recipient address to mark delivered?", US"");
 }
 
 action_required = US"-Mmd";
 dialog_ref_widget = menushell;
 create_dialog(US"Recipient address to mark delivered?", US"");
 }
 
-
 /*************************************************
 *   Cause all addresses to be marked delivered   *
 *************************************************/
 
 /*************************************************
 *   Cause all addresses to be marked delivered   *
 *************************************************/
 
-static void markalldelAction(Widget w, XtPointer client_data, XtPointer call_data)
+static void
+markalldelAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 {
-w = w;      /* Keep picky compilers happy */
-call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-Mmad", US"");
+ActOnMessage(US client_data, US"-Mmad", US"");
 }
 
 }
 
-
 /*************************************************
 *        Edit the message's sender               *
 *************************************************/
 
 /*************************************************
 *        Edit the message's sender               *
 *************************************************/
 
-static void editsenderAction(Widget w, XtPointer client_data,
-  XtPointer call_data)
+static void
+editsenderAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 queue_item *q;
 uschar *sender;
 {
 queue_item *q;
 uschar *sender;
-w = w;      /* Keep picky compilers happy */
-call_data = call_data;
-Ustrcpy(actioned_message, (uschar *)client_data);
+
+Ustrncpy(actioned_message, client_data, 24);
+actioned_message[23] = '\0';
 q = find_queue(actioned_message, queue_noop, 0);
 q = find_queue(actioned_message, queue_noop, 0);
-sender = (q == NULL)? US"" : (q->sender[0] == 0)? US"<>" : q->sender;
+sender = !q ? US"" : q->sender[0] == 0 ? US"<>" : q->sender;
 action_required = US"-Mes";
 dialog_ref_widget = menushell;
 create_dialog(US"New sender address?", sender);
 }
 
 action_required = US"-Mes";
 dialog_ref_widget = menushell;
 create_dialog(US"New sender address?", sender);
 }
 
-
 /*************************************************
 *    Cause a message to be returned to sender    *
 *************************************************/
 
 /*************************************************
 *    Cause a message to be returned to sender    *
 *************************************************/
 
-static void giveupAction(Widget w, XtPointer client_data, XtPointer call_data)
+static void
+giveupAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 {
-w = w;      /* Keep picky compilers happy */
-call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-v -Mg", US"");
+ActOnMessage(US client_data, US"-v -Mg", US"");
 }
 
 }
 
-
-
 /*************************************************
 *      Cause a message to be cancelled           *
 *************************************************/
 
 /*************************************************
 *      Cause a message to be cancelled           *
 *************************************************/
 
-static void removeAction(Widget w, XtPointer client_data, XtPointer call_data)
+static void
+removeAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 {
-w = w;      /* Keep picky compilers happy */
-call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-Mrm", US"");
+ActOnMessage(US client_data, US"-Mrm", US"");
 }
 
 }
 
-
-
 /*************************************************
 *             Display a message's headers        *
 *************************************************/
 
 /*************************************************
 *             Display a message's headers        *
 *************************************************/
 
-static void headersAction(Widget w, XtPointer client_data, XtPointer call_data)
+static void
+headersAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 uschar buffer[256];
 {
 uschar buffer[256];
-header_line *h, *next;
-Widget text = text_create((uschar *)client_data, text_depth);
-void *reset_point;
-
-w = w;      /* Keep picky compilers happy */
-call_data = call_data;
+Widget text = text_create(US client_data, text_depth);
+rmark reset_point;
 
 /* Remember the point in the dynamic store so we can recover to it afterwards.
 Then use Exim's function to read the header. */
 
 
 /* Remember the point in the dynamic store so we can recover to it afterwards.
 Then use Exim's function to read the header. */
 
-reset_point = store_get(0);
+reset_point = store_mark();
 
 
-sprintf(CS buffer, "%s-H", (uschar *)client_data);
+sprintf(CS buffer, "%s-H", US client_data);
 if (spool_read_header(buffer, TRUE, FALSE) != spool_read_OK)
   {
   if (errno == ERRNO_SPOOLFORMAT)
 if (spool_read_header(buffer, TRUE, FALSE) != spool_read_OK)
   {
   if (errno == ERRNO_SPOOLFORMAT)
@@ -661,8 +628,8 @@ if (spool_read_header(buffer, TRUE, FALSE) != spool_read_OK)
     struct stat statbuf;
     sprintf(CS big_buffer, "%s/input/%s", spool_directory, buffer);
     if (Ustat(big_buffer, &statbuf) == 0)
     struct stat statbuf;
     sprintf(CS big_buffer, "%s/input/%s", spool_directory, buffer);
     if (Ustat(big_buffer, &statbuf) == 0)
-      text_showf(text, "Format error in spool file %s: size=%d\n", buffer,
-        statbuf.st_size);
+      text_showf(text, "Format error in spool file %s: size=%lu\n", buffer,
+        (unsigned long)statbuf.st_size);
     else text_showf(text, "Format error in spool file %s\n", buffer);
     }
   else text_showf(text, "Read error for spool file %s\n", buffer);
     else text_showf(text, "Format error in spool file %s\n", buffer);
     }
   else text_showf(text, "Read error for spool file %s\n", buffer);
@@ -670,26 +637,22 @@ if (spool_read_header(buffer, TRUE, FALSE) != spool_read_OK)
   return;
   }
 
   return;
   }
 
-if (sender_address != NULL)
-  {
-  text_showf(text, "%s sender: <%s>\n", sender_local? "Local" : "Remote",
+if (sender_address)
+  text_showf(text, "%s sender: <%s>\n", f.sender_local ? "Local" : "Remote",
     sender_address);
     sender_address);
-  }
 
 
-if (recipients_list != NULL)
+if (recipients_list)
   {
   {
-  int i;
   text_show(text, US"Recipients:\n");
   text_show(text, US"Recipients:\n");
-  for (i = 0; i < recipients_count; i++)
-    {
+  for (int i = 0; i < recipients_count; i++)
     text_showf(text, "  %s %s\n",
     text_showf(text, "  %s %s\n",
-      (tree_search(tree_nonrecipients, recipients_list[i].address) == NULL)?
-        " ":"*", recipients_list[i].address);
-    }
+      tree_search(tree_nonrecipients, recipients_list[i].address)
+        ? "*" : " ",
+      recipients_list[i].address);
   text_show(text, US"\n");
   }
 
   text_show(text, US"\n");
   }
 
-for (h = header_list; h != NULL; h = next)
+for (header_line * next, * h = header_list; h; h = next)
   {
   next = h->next;
   text_showf(text, "%c ", h->type);   /* Don't push h->text through a %s */
   {
   next = h->next;
   text_showf(text, "%c ", h->type);   /* Don't push h->text through a %s */
@@ -699,20 +662,13 @@ for (h = header_list; h != NULL; h = next)
 store_reset(reset_point);
 }
 
 store_reset(reset_point);
 }
 
-
-
-
 /*************************************************
 *              Dismiss a text window             *
 *************************************************/
 
 /*************************************************
 *              Dismiss a text window             *
 *************************************************/
 
-static void dismissAction(Widget w, XtPointer client_data, XtPointer call_data)
+static void
+dismissAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 {
-pipe_item *p = pipe_chain;
-
-w = w;      /* Keep picky compilers happy */
-call_data = call_data;
-
 XtPopdown((Widget)client_data);
 XtDestroyWidget((Widget)client_data);
 
 XtPopdown((Widget)client_data);
 XtDestroyWidget((Widget)client_data);
 
@@ -721,16 +677,9 @@ the chain so that subsequent data doesn't try to use it. We have
 to search the parents of the saved widget to see if one of them
 is what we have just destroyed. */
 
 to search the parents of the saved widget to see if one of them
 is what we have just destroyed. */
 
-while (p != NULL)
-  {
-  Widget pp = p->widget;
-  while (pp != NULL)
-    {
+for (pipe_item * p = pipe_chain; p; p = p->next)
+  for (Widget pp = p->widget; pp; pp = XtParent(pp))
     if (pp == (Widget)client_data) { p->widget = NULL; return; }
     if (pp == (Widget)client_data) { p->widget = NULL; return; }
-    pp = XtParent(pp);
-    }
-  p = p->next;
-  }
 }
 
 
 }
 
 
@@ -739,7 +688,8 @@ while (p != NULL)
 *             Set up popup text window           *
 *************************************************/
 
 *             Set up popup text window           *
 *************************************************/
 
-static Widget text_create(uschar *name, int height)
+static Widget
+text_create(uschar *name, int height)
 {
 Widget textshell, form, text, button;
 
 {
 Widget textshell, form, text, button;
 
@@ -790,9 +740,6 @@ XtPopup(textshell, XtGrabNone);
 return text;
 }
 
 return text;
 }
 
-
-
-
 /*************************************************
 *            Set up menu in queue window         *
 *************************************************/
 /*************************************************
 *            Set up menu in queue window         *
 *************************************************/
@@ -800,7 +747,8 @@ return text;
 /* We have added an action table that causes this function to
 be called, and set up button 2 in the text widgets to call it. */
 
 /* We have added an action table that causes this function to
 be called, and set up button 2 in the text widgets to call it. */
 
-void menu_create(Widget w, XEvent *event, String *actargs, Cardinal *count)
+void
+menu_create(Widget w, XEvent *event, String *actargs, Cardinal *count)
 {
 int line;
 int i;
 {
 int line;
 int i;
@@ -816,9 +764,6 @@ XtTranslations menu_trans = XtParseTranslationTable(
    <BtnUp>:         MenuPopdown()notify()unhighlight()\n\
   ");
 
    <BtnUp>:         MenuPopdown()notify()unhighlight()\n\
   ");
 
-actargs = actargs;   /* Keep picky compilers happy */
-count = count;
-
 /* Get the sink and source and the current text pointer */
 
 queue_get_arg[0].value = (XtArgVal)(&queue_text_sink);
 /* Get the sink and source and the current text pointer */
 
 queue_get_arg[0].value = (XtArgVal)(&queue_text_sink);
@@ -880,7 +825,7 @@ while (p > 0 && s[p+11] == ' ')
 
 /* Now pointing at first character of a main line. */
 
 
 /* Now pointing at first character of a main line. */
 
-Ustrncpy(message_id, s+p+11, MESSAGE_ID_LENGTH);
+Ustrncpy(message_id, s+p+11, MESSAGE_ID_LENGTH);       /*III*/
 message_id[MESSAGE_ID_LENGTH] = 0;
 
 /* Highlight the line being menued, and save its parameters so that it
 message_id[MESSAGE_ID_LENGTH] = 0;
 
 /* Highlight the line being menued, and save its parameters so that it