Index: functions.c
===================================================================
--- functions.c	(revision a16d7e5b1281bf21e0fe52b6d9946fd58893da28)
+++ functions.c	(revision a16d7e5b1281bf21e0fe52b6d9946fd58893da28)
@@ -662,4 +662,34 @@
 }
 
+void owl_function_delete_and_expunge_message(int n)
+{
+  owl_messagelist *ml = owl_global_get_msglist(&g);
+  owl_view *v = owl_global_get_current_view(&g);
+  int lastmsgid = owl_function_get_curmsg_id(v);
+
+  /* delete and expunge the message */
+  owl_messagelist_delete_and_expunge_element(ml, n);
+
+  owl_function_redisplay_to_nearest(lastmsgid, v);
+}
+
+void owl_function_delete_and_expunge_cur(bool exclaim_success)
+{
+  int curmsg;
+  const owl_view *v = owl_global_get_current_view(&g);
+
+  /* bail if there's no current message */
+  if (owl_view_get_size(v) < 1) {
+    owl_function_error("No current message to delete");
+    return;
+  }
+
+  /* delete the current message */
+  curmsg = owl_global_get_curmsg(&g);
+  owl_function_delete_and_expunge_message(curmsg);
+  if (exclaim_success)
+    owl_function_makemsg("Message deleted and expunged");
+}
+
 /* if move_after is 1, moves after the delete */
 void owl_function_deletecur(int move_after)
@@ -721,38 +751,60 @@
 }
 
+/* returns the current message id, if it exists.  Otherwise returns
+ * -1 if we are past the end of the message list, and 0 otherwise. */
+int owl_function_get_curmsg_id(const owl_view *v)
+{
+  int curmsg = owl_global_get_curmsg(&g);
+  const owl_message *m = owl_view_get_element(v, curmsg);
+  if (m)
+    return owl_message_get_id(m);
+  if (curmsg > 0) /* past the end of the message list (probably) */
+    return -1;
+  return 0;
+}
+
+/* redisplays the view to the nearest message to the id given.
+ * if msgid < 0, redisplay to past the end of the message list */
+void owl_function_redisplay_to_nearest(int msgid, owl_view *v)
+{
+  int curmsg;
+  /* update all views (we only have one right now) */
+  owl_view_recalculate(v);
+
+  /* find where the new position should be */
+  if (msgid < 0) {
+    /* If already at the end, blank the screen and move curmsg
+     * past the end of the messages. */
+    curmsg = owl_view_get_size(v);
+    owl_global_set_topmsg(&g, curmsg);
+    owl_global_set_curmsg(&g, curmsg);
+  } else {
+    curmsg = owl_view_get_nearest_to_msgid(v, msgid);
+    if (curmsg > owl_view_get_size(v) - 1)
+      curmsg = owl_view_get_size(v) - 1;
+    if (curmsg < 0)
+      curmsg = 0;
+    owl_global_set_curmsg(&g, curmsg);
+    owl_function_calculate_topmsg(OWL_DIRECTION_NONE);
+  }
+  /* if there are no messages set the direction to down in case we
+   * delete everything upwards */
+  owl_global_set_direction_downwards(&g);
+
+  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
+}
+
 void owl_function_expunge(void)
 {
-  int curmsg;
-  const owl_message *m;
-  owl_messagelist *ml;
-  owl_view *v;
-  int lastmsgid=0;
-
-  curmsg=owl_global_get_curmsg(&g);
-  v=owl_global_get_current_view(&g);
-  ml=owl_global_get_msglist(&g);
-
-  m=owl_view_get_element(v, curmsg);
-  if (m) lastmsgid = owl_message_get_id(m);
+  owl_messagelist *ml = owl_global_get_msglist(&g);
+  owl_view *v = owl_global_get_current_view(&g);
+  int lastmsgid = owl_function_get_curmsg_id(v);
 
   /* expunge the message list */
   owl_messagelist_expunge(ml);
 
-  /* update all views (we only have one right now) */
-  owl_view_recalculate(v);
-
-  /* find where the new position should be
-     (as close as possible to where we last where) */
-  curmsg = owl_view_get_nearest_to_msgid(v, lastmsgid);
-  if (curmsg>owl_view_get_size(v)-1) curmsg = owl_view_get_size(v)-1;
-  if (curmsg<0) curmsg = 0;
-  owl_global_set_curmsg(&g, curmsg);
-  owl_function_calculate_topmsg(OWL_DIRECTION_NONE);
-  /* if there are no messages set the direction to down in case we
-     delete everything upwards */
-  owl_global_set_direction_downwards(&g);
+  owl_function_redisplay_to_nearest(lastmsgid, v);
   
   owl_function_makemsg("Messages expunged");
-  owl_mainwin_redisplay(owl_global_get_mainwin(&g));
 }
 
@@ -1642,4 +1694,17 @@
 }
 
+void owl_function_delete_and_expunge_by_id(int id, bool exclaim_success)
+{
+  const owl_messagelist *ml = owl_global_get_msglist(&g);
+  int msg = owl_messagelist_get_index_by_id(ml, id);
+  if (msg < 0) {
+    owl_function_error("No message with id %d: unable to delete", id);
+  } else {
+    owl_function_delete_and_expunge_message(msg);
+    if (exclaim_success)
+      owl_function_makemsg("Message deleted and expunged");
+  }
+}
+
 /* note: this applies to global message list, not to view.
  * If flag is 1, deletes.  If flag is 0, undeletes. */
