Index: commands.c
===================================================================
--- commands.c	(revision f271129fbb186598811b923e406d65f9d2b3031a)
+++ commands.c	(revision c8ef50b948941e905b8fd8356002fc8014f22c8d)
@@ -2796,5 +2796,13 @@
     owl_history_store(hist, owl_editwin_get_text(e), false);
 
+  /* Take a reference to the editwin, so that it survives the pop
+   * context. TODO: We should perhaps refcount or otherwise protect
+   * the context so that, even if a command pops a context, the
+   * context itself will last until the command returns. */
+  owl_editwin_ref(e);
   owl_global_pop_context(&g);
+
+  owl_editwin_do_callback(e, false);
+  owl_editwin_unref(e);
 }
 
@@ -2856,5 +2864,5 @@
   owl_global_pop_context(&g);
 
-  owl_editwin_do_callback(e);
+  owl_editwin_do_callback(e, true);
   owl_editwin_unref(e);
 }
Index: editwin.c
===================================================================
--- editwin.c	(revision f271129fbb186598811b923e406d65f9d2b3031a)
+++ editwin.c	(revision c8ef50b948941e905b8fd8356002fc8014f22c8d)
@@ -33,5 +33,5 @@
   oe_excursion *excursions;
 
-  void (*callback)(struct _owl_editwin*);
+  void (*callback)(struct _owl_editwin *e, bool success);
   void (*destroy_cbdata)(void *);
   void *cbdata;
@@ -220,10 +220,10 @@
 }
 
-void owl_editwin_set_callback(owl_editwin *e, void (*cb)(owl_editwin*))
+void owl_editwin_set_callback(owl_editwin *e, void (*cb)(owl_editwin *, bool))
 {
   e->callback = cb;
 }
 
-void (*owl_editwin_get_callback(owl_editwin *e))(owl_editwin*)
+void (*owl_editwin_get_callback(owl_editwin *e))(owl_editwin *, bool)
 {
   return e->callback;
@@ -248,12 +248,12 @@
 }
 
-void owl_editwin_do_callback(owl_editwin *e) {
-  void (*cb)(owl_editwin*);
-  cb=owl_editwin_get_callback(e);
-  if(!cb) {
+void owl_editwin_do_callback(owl_editwin *e, bool success)
+{
+  void (*cb)(owl_editwin *, bool);
+  cb = owl_editwin_get_callback(e);
+  if (!cb) {
     owl_function_error("Internal error: No editwin callback!");
   } else {
-    /* owl_function_error("text: |%s|", owl_editwin_get_text(e)); */
-    cb(e);
+    cb(e, success);
   }
 }
Index: functions.c
===================================================================
--- functions.c	(revision 6646fdb981a88a6548cbc3da4b4963330fe1c7d6)
+++ functions.c	(revision c8ef50b948941e905b8fd8356002fc8014f22c8d)
@@ -272,5 +272,5 @@
 }
 
-void owl_function_start_edit_win(const char *line, void (*callback)(owl_editwin *), void *data, void (*cleanup)(void *))
+owl_editwin *owl_function_start_edit_win(const char *line)
 {
   owl_editwin *e;
@@ -286,10 +286,8 @@
   g_free(s);
 
-  owl_editwin_set_cbdata(e, data, cleanup);
-  owl_editwin_set_callback(e, callback);
   ctx = owl_editcontext_new(OWL_CTX_EDITMULTI, e, "editmulti",
                             owl_global_deactivate_editcontext, &g);
   owl_global_push_context_obj(&g, ctx);
-
+  return e;
 }
 
@@ -309,4 +307,5 @@
 void owl_function_zwrite_setup(owl_zwrite *z)
 {
+  owl_editwin *e;
   /* send a ping if necessary */
   if (owl_global_is_txping(&g)) {
@@ -316,19 +315,19 @@
 
   owl_function_write_setup("zephyr");
-  owl_function_start_edit_win(z->zwriteline,
-                              &owl_callback_zwrite,
-                              z, (void(*)(void*))owl_zwrite_delete);
+  e = owl_function_start_edit_win(z->zwriteline);
+  owl_editwin_set_cbdata(e, z, (void (*)(void *))owl_zwrite_delete);
+  owl_editwin_set_callback(e, &owl_callback_zwrite);
 }
 
 void owl_function_aimwrite_setup(const char *to)
 {
+  owl_editwin *e;
   /* TODO: We probably actually want an owl_aimwrite object like
    * owl_zwrite. */
   char *line = g_strdup_printf("aimwrite %s", to);
   owl_function_write_setup("message");
-  owl_function_start_edit_win(line,
-                              &owl_callback_aimwrite,
-                              g_strdup(to),
-                              g_free);
+  e = owl_function_start_edit_win(line);
+  owl_editwin_set_cbdata(e, g_strdup(to), g_free);
+  owl_editwin_set_callback(e, &owl_callback_aimwrite);
   g_free(line);
 }
@@ -336,11 +335,13 @@
 void owl_function_loopwrite_setup(void)
 {
+  owl_editwin *e;
   owl_function_write_setup("message");
-  owl_function_start_edit_win("loopwrite",
-                              &owl_callback_loopwrite,
-                              NULL, NULL);
-}
-
-void owl_callback_zwrite(owl_editwin *e) {
+  e = owl_function_start_edit_win("loopwrite");
+  owl_editwin_set_callback(e, &owl_callback_loopwrite);
+}
+
+void owl_callback_zwrite(owl_editwin *e, bool success)
+{
+  if (!success) return;
   owl_zwrite *z = owl_editwin_get_cbdata(e);
   owl_function_zwrite(z, owl_editwin_get_text(e));
@@ -437,5 +438,7 @@
 }
 
-void owl_callback_aimwrite(owl_editwin *e) {
+void owl_callback_aimwrite(owl_editwin *e, bool success)
+{
+  if (!success) return;
   char *to = owl_editwin_get_cbdata(e);
   owl_function_aimwrite(to, owl_editwin_get_text(e), true);
@@ -501,5 +504,7 @@
 }
 
-void owl_callback_loopwrite(owl_editwin *e) {
+void owl_callback_loopwrite(owl_editwin *e, bool success)
+{
+  if (!success) return;
   owl_function_loopwrite(owl_editwin_get_text(e));
 }
@@ -912,5 +917,7 @@
 }
 
-void owl_callback_aimlogin(owl_editwin *e) {
+void owl_callback_aimlogin(owl_editwin *e, bool success)
+{
+  if (!success) return;
   char *user = owl_editwin_get_cbdata(e);
   owl_function_aimlogin(user,
@@ -1934,6 +1941,7 @@
 }
 
-void owl_callback_command(owl_editwin *e)
-{
+void owl_callback_command(owl_editwin *e, bool success)
+{
+  if (!success) return;
   char *rv;
   const char *line = owl_editwin_get_text(e);
@@ -1946,5 +1954,5 @@
 }
 
-void owl_function_start_command(const char *line)
+owl_editwin *owl_function_start_command(const char *line)
 {
   owl_editwin *tw;
@@ -1961,7 +1969,8 @@
   owl_global_push_context_obj(&g, ctx);
   owl_editwin_set_callback(tw, owl_callback_command);
-}
-
-CALLER_OWN owl_editwin *owl_function_start_question(const char *line)
+  return tw;
+}
+
+owl_editwin *owl_function_start_question(const char *line)
 {
   owl_editwin *tw;
@@ -1978,5 +1987,5 @@
 }
 
-CALLER_OWN owl_editwin *owl_function_start_password(const char *line)
+owl_editwin *owl_function_start_password(const char *line)
 {
   owl_editwin *tw;
Index: perl/lib/BarnOwl.pm
===================================================================
--- perl/lib/BarnOwl.pm	(revision a130fc5ed65377322966cc9423b3e4674197922c)
+++ perl/lib/BarnOwl.pm	(revision c8ef50b948941e905b8fd8356002fc8014f22c8d)
@@ -9,4 +9,5 @@
                     zephyr_stylestrip zephyr_smartstrip_user zephyr_getsubs
                     queue_message admin_message
+                    start_edit
                     start_question start_password start_edit_win
                     get_data_dir get_config_dir popless_text popless_ztext
@@ -105,6 +106,5 @@
 Enqueue a message in the BarnOwl message list, logging it and
 processing it appropriately. C<MESSAGE> should be an instance of
-BarnOwl::Message or a subclass.  Returns the queued message.  This
-is useful for, e.g., deleting a message from the message list.
+BarnOwl::Message or a subclass.
 
 =head2 admin_message HEADER BODY
@@ -112,20 +112,90 @@
 Display a BarnOwl B<Admin> message, with the given header and body.
 
+=head2 start_edit %ARGS
+
+Displays a prompt on the screen and lets the user enter text,
+and calls a callback when the editwin is closed.
+
+C<%ARGS> must contain the following keys:
+
+=over 4
+
+=item prompt
+
+The line to display on the screen
+
+=item type
+
+One of:
+
+=over 4
+
+=item edit_win
+
+Displays the prompt on a line of its own and opens the edit_win.
+
+=item question
+
+Displays prompt on the screen and lets the user enter a line of
+text.
+
+=item password
+
+Like question, but echoes the user's input as C<*>s when they
+input.
+
+=back
+
+=item callback
+
+A Perl subroutine that is called when the user closes the edit_win.
+C<CALLBACK> gets called with two parameters: the text the user entered,
+and a C<SUCCESS> boolean parameter which is false if the user canceled
+the edit_win and true otherwise.
+
+=back
+
 =head2 start_question PROMPT CALLBACK
 
-Displays C<PROMPT> on the screen and lets the user enter a line of
-text, and calls C<CALLBACK>, which must be a perl subroutine
-reference, with the text the user entered
-
 =head2 start_password PROMPT CALLBACK
 
-Like C<start_question>, but echoes the user's input as C<*>s when they
-input.
-
 =head2 start_edit_win PROMPT CALLBACK
 
-Like C<start_question>, but displays C<PROMPT> on a line of its own
-and opens the editwin. If the user cancels the edit win, C<CALLBACK>
-is not invoked.
+Roughly equivalent to C<start_edit> called with the appropriate parameters.
+C<CALLBACK> is only called on success.
+
+These are deprecated wrappers around L<BarnOwl::start_edit>, and should not
+be uesd in new code.
+
+=cut
+
+sub start_edit {
+    my %args = (@_);
+    BarnOwl::Internal::start_edit($args{type}, $args{prompt}, $args{callback});
+}
+
+sub start_question {
+    my ($prompt, $callback) = @_;
+    BarnOwl::start_edit(type => 'question', prompt => $prompt, callback => sub {
+            my ($text, $success) = @_;
+            $callback->($text) if $success;
+        });
+}
+
+sub start_password {
+    my ($prompt, $callback) = @_;
+    BarnOwl::start_edit(type => 'password', prompt => $prompt, callback => sub {
+            my ($text, $success) = @_;
+            $callback->($text) if $success;
+        });
+}
+
+sub start_edit_win {
+    my ($prompt, $callback) = @_;
+    BarnOwl::start_edit(type => 'edit_win', prompt => $prompt, callback => sub {
+            my ($text, $success) = @_;
+            $callback->($text) if $success;
+        });
+}
 
 =head2 get_data_dir
Index: perlconfig.c
===================================================================
--- perlconfig.c	(revision b9517cf7ce2959a6e86a52d25a98b1d03df56d58)
+++ perlconfig.c	(revision c8ef50b948941e905b8fd8356002fc8014f22c8d)
@@ -520,5 +520,5 @@
 }
 
-void owl_perlconfig_edit_callback(owl_editwin *e)
+void owl_perlconfig_edit_callback(owl_editwin *e, bool success)
 {
   SV *cb = owl_editwin_get_cbdata(e);
@@ -537,4 +537,5 @@
   PUSHMARK(SP);
   XPUSHs(sv_2mortal(text));
+  XPUSHs(sv_2mortal(newSViv(success)));
   PUTBACK;
   
Index: perlglue.xs
===================================================================
--- perlglue.xs	(revision f271129fbb186598811b923e406d65f9d2b3031a)
+++ perlglue.xs	(revision 8ad3964885f1491ed791b5266e62245dadde6948)
@@ -167,57 +167,4 @@
 	}
 
-void
-start_question(line, callback)
-	const char *line
-	SV *callback
-	PREINIT:
-		owl_editwin *e;
-	CODE:
-	{
-		if(!SV_IS_CODEREF(callback))
-			croak("Callback must be a subref");
-
-		e = owl_function_start_question(line);
-
-		owl_editwin_set_cbdata(e,
-				       newSVsv(callback),
-				       owl_perlconfig_dec_refcnt);
-		owl_editwin_set_callback(e, owl_perlconfig_edit_callback);
-	}
-
-void
-start_password(line, callback)
-	const char *line
-	SV *callback
-	PREINIT:
-		owl_editwin *e;
-	CODE:
-	{
-		if(!SV_IS_CODEREF(callback))
-			croak("Callback must be a subref");
-
-		e = owl_function_start_password(line);
-
-		owl_editwin_set_cbdata(e,
-				       newSVsv(callback),
-				       owl_perlconfig_dec_refcnt);
-		owl_editwin_set_callback(e, owl_perlconfig_edit_callback);
-	}
-
-void
-start_edit_win(line, callback)
-	const char *line
-	SV *callback
-	CODE:
-	{
-		if(!SV_IS_CODEREF(callback))
-			croak("Callback must be a subref");
-
-		owl_function_start_edit_win(line,
-					    owl_perlconfig_edit_callback,
-					    newSVsv(callback),
-					    owl_perlconfig_dec_refcnt);
-	}
-
 
 const char * 
@@ -496,4 +443,29 @@
 				      ival);
 
+void
+start_edit(edit_type, line, callback)
+	const char *edit_type
+	const char *line
+	SV *callback
+	PREINIT:
+		owl_editwin *e;
+	CODE:
+	{
+		if (!SV_IS_CODEREF(callback))
+			croak("Callback must be a subref");
+
+		if (!strcmp(edit_type, "question"))
+			e = owl_function_start_question(line);
+		else if (!strcmp(edit_type, "password"))
+			e = owl_function_start_password(line);
+		else if (!strcmp(edit_type, "edit_win"))
+			e = owl_function_start_edit_win(line);
+		else
+			croak("edit_type must be one of 'password', 'question', 'edit_win', not '%s'", edit_type);
+
+		owl_editwin_set_cbdata(e, newSVsv(callback), owl_perlconfig_dec_refcnt);
+		owl_editwin_set_callback(e, owl_perlconfig_edit_callback);
+	}
+
 MODULE = BarnOwl		PACKAGE = BarnOwl::Editwin
 
Index: viewwin.c
===================================================================
--- viewwin.c	(revision f271129fbb186598811b923e406d65f9d2b3031a)
+++ viewwin.c	(revision c8ef50b948941e905b8fd8356002fc8014f22c8d)
@@ -158,6 +158,7 @@
 } owl_viewwin_search_data;
 
-static void owl_viewwin_callback_search(owl_editwin *e)
-{
+static void owl_viewwin_callback_search(owl_editwin *e, bool success)
+{
+  if (!success) return;
   int consider_current = false;
   const char *line = owl_editwin_get_text(e);
