unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
* Concerns regarding some library functions
@ 2011-09-27 13:25 Ali Polatel
  2011-09-27 16:59 ` David Bremner
  2011-09-28 15:42 ` Concerns regarding some library functions Sebastian Spaeth
  0 siblings, 2 replies; 30+ messages in thread
From: Ali Polatel @ 2011-09-27 13:25 UTC (permalink / raw)
  To: notmuch

[-- Attachment #1: Type: text/plain, Size: 1548 bytes --]

Hello,

Being the maintainer of Ruby bindings, I've been watching the
development of API changes closely. Ruby bindings are nearly complete
with the exception of two functions which I think are poorly implemented
in terms of error handling.

The two functions I've mentioned above are
notmuch_database_find_message() and
notmuch_database_find_message_by_filename().

The problem with their design is NULL return may both mean an error
condition and "message not found". However, we already have a similar
function which does not have such a flaw, namely notmuch_database_add_message().

In my humble opinion it is a good idea to modify these functions to
return 'notmuch_status_t' and add an argument 'notmuch_message_t **'
which will be initialized to the message object upon successful return.
This is just like notmuch_database_add_message() which provides both
consistency and proper error reporting.

I vaguely remember this question was raised on the list for
notmuch_database_find_message() before. Seeing the recent addition of
notmuch_database_find_message_by_filename(), I wanted to bring this up
again in the hope to get it fixed as soon as possible.

I am not providing a patch here considering the simplicity of the
problem but if anyone needs elaboration, I will be happy to submit a
patch.

P.S.: Ruby bindings don't have wrappers for these functions but I am not
sure about Python bindings and how they solve, or 'hack around', this
problem. CC'ing Sebastian for comments so we can have consistency
between bindings.

        -alip

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Concerns regarding some library functions
  2011-09-27 13:25 Concerns regarding some library functions Ali Polatel
@ 2011-09-27 16:59 ` David Bremner
  2011-09-27 22:46   ` Austin Clements
  2011-09-28 15:42 ` Concerns regarding some library functions Sebastian Spaeth
  1 sibling, 1 reply; 30+ messages in thread
From: David Bremner @ 2011-09-27 16:59 UTC (permalink / raw)
  To: Ali Polatel, notmuch; +Cc: Austin Clements

On Tue, 27 Sep 2011 16:25:58 +0300, Ali Polatel <polatel@gmail.com> wrote:

> The problem with their design is NULL return may both mean an error
> condition and "message not found". However, we already have a similar
> function which does not have such a flaw, namely notmuch_database_add_message().

So, I take there is no way to distinguish those two outcomes? That does
sound bad. Looking at the code for notmuch-new, it looks like the return
value of notmuch_database_find_message_by_filename is used without
checking it for NULL.  Austin, can you comment on that at all?

> I am not providing a patch here considering the simplicity of the
> problem but if anyone needs elaboration, I will be happy to submit a
> patch.

Well, also all the places that call these functions in the library and
command line client would need to be modified, as well as the go and
python bindings.  So it isn't completely trivial. Nor is is terribly
difficult of course.

d

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Concerns regarding some library functions
  2011-09-27 16:59 ` David Bremner
@ 2011-09-27 22:46   ` Austin Clements
  2011-09-28  7:53     ` Ali Polatel
  0 siblings, 1 reply; 30+ messages in thread
From: Austin Clements @ 2011-09-27 22:46 UTC (permalink / raw)
  To: Ali Polatel, David Bremner; +Cc: notmuch

Quoth David Bremner on Sep 27 at  1:59 pm:
> On Tue, 27 Sep 2011 16:25:58 +0300, Ali Polatel <polatel@gmail.com> wrote:
> 
> > The problem with their design is NULL return may both mean an error
> > condition and "message not found". However, we already have a similar
> > function which does not have such a flaw, namely notmuch_database_add_message().
> 
> So, I take there is no way to distinguish those two outcomes? That does
> sound bad. Looking at the code for notmuch-new, it looks like the return
> value of notmuch_database_find_message_by_filename is used without
> checking it for NULL.  Austin, can you comment on that at all?

I'd be happy to distinguish these outcomes.  I did
notmuch_database_find_message_by_filename the way I did only to be
consistent with notmuch_database_find_message.  Since ndfmbf isn't
entrenched yet, now is a good time to change it.

The call in notmuch-new should check the return, though if it can't
find the message at that point, something has gone terribly wrong.
Segfaulting is never the answer, though.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Concerns regarding some library functions
  2011-09-27 22:46   ` Austin Clements
@ 2011-09-28  7:53     ` Ali Polatel
  2011-09-29 14:51       ` Austin Clements
  0 siblings, 1 reply; 30+ messages in thread
From: Ali Polatel @ 2011-09-28  7:53 UTC (permalink / raw)
  To: Austin Clements, David Bremner; +Cc: notmuch

[-- Attachment #1: Type: text/plain, Size: 1490 bytes --]

On Tue, 27 Sep 2011 18:46:22 -0400, Austin Clements <amdragon@MIT.EDU> wrote:
> Quoth David Bremner on Sep 27 at  1:59 pm:
> > On Tue, 27 Sep 2011 16:25:58 +0300, Ali Polatel <polatel@gmail.com> wrote:
> > 
> > > The problem with their design is NULL return may both mean an error
> > > condition and "message not found". However, we already have a similar
> > > function which does not have such a flaw, namely notmuch_database_add_message().
> > 
> > So, I take there is no way to distinguish those two outcomes? That does
> > sound bad. Looking at the code for notmuch-new, it looks like the return
> > value of notmuch_database_find_message_by_filename is used without
> > checking it for NULL.  Austin, can you comment on that at all?
> 
> I'd be happy to distinguish these outcomes.  I did
> notmuch_database_find_message_by_filename the way I did only to be
> consistent with notmuch_database_find_message.  Since ndfmbf isn't
> entrenched yet, now is a good time to change it.

What about notmuch_database_find_message()? If we leave it as it is,
this will lead to inconsistency and if we change it, we need to think
about API breakage issues.

> The call in notmuch-new should check the return, though if it can't
> find the message at that point, something has gone terribly wrong.
> Segfaulting is never the answer, though.

Indeed, just not to step on each other's feet, are you going to write a
patch or shall I start writing one?

         -alip

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Concerns regarding some library functions
  2011-09-27 13:25 Concerns regarding some library functions Ali Polatel
  2011-09-27 16:59 ` David Bremner
@ 2011-09-28 15:42 ` Sebastian Spaeth
  1 sibling, 0 replies; 30+ messages in thread
From: Sebastian Spaeth @ 2011-09-28 15:42 UTC (permalink / raw)
  To: Ali Polatel, notmuch

[-- Attachment #1: Type: text/plain, Size: 925 bytes --]

On Tue, 27 Sep 2011 16:25:58 +0300, Ali Polatel wrote:
> The two functions I've mentioned above are
> notmuch_database_find_message() and
> notmuch_database_find_message_by_filename().
> 
> The problem with their design is NULL return may both mean an error
> condition and "message not found". However, we already have a similar
> function which does not have such a flaw, namely notmuch_database_add_message().

Yes, this is because NULL used to mean message not found and NULL means
error was tacked on later (because cworth did not expect that xapian
would actually throw errors that often (such as database modified and
whatnot). So the meaning of NULL is, ahhem, suboptimal...

ERROR or really not there? There are mails from me, commenting on
that. I would welcome receiving back a notmuch_status_t value and have a
separate notmuch_message_t parameter which receives the actual message.

Sebastian

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Concerns regarding some library functions
  2011-09-28  7:53     ` Ali Polatel
@ 2011-09-29 14:51       ` Austin Clements
  2011-09-29 19:59         ` David Bremner
  2011-09-30  6:47         ` Concerns regarding some library functions Ali Polatel
  0 siblings, 2 replies; 30+ messages in thread
From: Austin Clements @ 2011-09-29 14:51 UTC (permalink / raw)
  To: Ali Polatel; +Cc: notmuch

Quoth Ali Polatel on Sep 28 at 10:53 am:
> On Tue, 27 Sep 2011 18:46:22 -0400, Austin Clements <amdragon@MIT.EDU> wrote:
> > Quoth David Bremner on Sep 27 at  1:59 pm:
> > > On Tue, 27 Sep 2011 16:25:58 +0300, Ali Polatel <polatel@gmail.com> wrote:
> > > 
> > > > The problem with their design is NULL return may both mean an error
> > > > condition and "message not found". However, we already have a similar
> > > > function which does not have such a flaw, namely notmuch_database_add_message().
> > > 
> > > So, I take there is no way to distinguish those two outcomes? That does
> > > sound bad. Looking at the code for notmuch-new, it looks like the return
> > > value of notmuch_database_find_message_by_filename is used without
> > > checking it for NULL.  Austin, can you comment on that at all?
> > 
> > I'd be happy to distinguish these outcomes.  I did
> > notmuch_database_find_message_by_filename the way I did only to be
> > consistent with notmuch_database_find_message.  Since ndfmbf isn't
> > entrenched yet, now is a good time to change it.
> 
> What about notmuch_database_find_message()? If we leave it as it is,
> this will lead to inconsistency and if we change it, we need to think
> about API breakage issues.

Yes.  We could just deal with that (there aren't *that* many API
consumers).  For binary compatibility, I suppose we could even use
symbol versioning.

> > The call in notmuch-new should check the return, though if it can't
> > find the message at that point, something has gone terribly wrong.
> > Segfaulting is never the answer, though.
> 
> Indeed, just not to step on each other's feet, are you going to write a
> patch or shall I start writing one?

Please feel free to write a patch.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Concerns regarding some library functions
  2011-09-29 14:51       ` Austin Clements
@ 2011-09-29 19:59         ` David Bremner
  2011-09-29 20:15           ` Austin Clements
  2011-09-30  6:47         ` Concerns regarding some library functions Ali Polatel
  1 sibling, 1 reply; 30+ messages in thread
From: David Bremner @ 2011-09-29 19:59 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

On Thu, 29 Sep 2011 10:51:29 -0400, Austin Clements <amdragon@MIT.EDU> wrote:

> Yes.  We could just deal with that (there aren't *that* many API
> consumers).  For binary compatibility, I suppose we could even use
> symbol versioning.

I noticed a similar remark in lib/Makefile.local. But I'm not sure how
this work if the interface of a given library function changed.  Can
someone point me to some more explanation? 

Of course we can always bump the soname of libnotmuch. It isn't that big
of a deal IMHO.

d

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Concerns regarding some library functions
  2011-09-29 19:59         ` David Bremner
@ 2011-09-29 20:15           ` Austin Clements
  2011-10-04 11:18             ` David Bremner
  0 siblings, 1 reply; 30+ messages in thread
From: Austin Clements @ 2011-09-29 20:15 UTC (permalink / raw)
  To: David Bremner; +Cc: notmuch

Quoth David Bremner on Sep 29 at  4:59 pm:
> On Thu, 29 Sep 2011 10:51:29 -0400, Austin Clements <amdragon@MIT.EDU> wrote:
> 
> > Yes.  We could just deal with that (there aren't *that* many API
> > consumers).  For binary compatibility, I suppose we could even use
> > symbol versioning.
> 
> I noticed a similar remark in lib/Makefile.local. But I'm not sure how
> this work if the interface of a given library function changed.  Can
> someone point me to some more explanation? 

With symbol versioning we'd still provide the old function (presumably
re-implemented in terms of the new function).  Both would wind up in
the .so and old binaries would still link against the old symbol.  It
doesn't help that much once something gets recompiled; assuming the
source isn't requesting a specific version of a symbol, it will try to
use the latest version.

That, however, is about the extent of my knowledge on symbol
versioning.  It's possible this simply doesn't work with symbols that
don't already have a version; I'm not sure.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Concerns regarding some library functions
  2011-09-29 14:51       ` Austin Clements
  2011-09-29 19:59         ` David Bremner
@ 2011-09-30  6:47         ` Ali Polatel
  2011-10-01  8:12           ` [PATCH] lib: make find_message{,by_filename) report errors Ali Polatel
  1 sibling, 1 reply; 30+ messages in thread
From: Ali Polatel @ 2011-09-30  6:47 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

[-- Attachment #1: Type: text/plain, Size: 15556 bytes --]

Austin Clements yazmış:
>Quoth Ali Polatel on Sep 28 at 10:53 am:
>> On Tue, 27 Sep 2011 18:46:22 -0400, Austin Clements <amdragon@MIT.EDU> wrote:
>> > Quoth David Bremner on Sep 27 at  1:59 pm:
>> > > On Tue, 27 Sep 2011 16:25:58 +0300, Ali Polatel <polatel@gmail.com> wrote:
>> > >
>> > > > The problem with their design is NULL return may both mean an error
>> > > > condition and "message not found". However, we already have a similar
>> > > > function which does not have such a flaw, namely notmuch_database_add_message().
>> > >
>> > > So, I take there is no way to distinguish those two outcomes? That does
>> > > sound bad. Looking at the code for notmuch-new, it looks like the return
>> > > value of notmuch_database_find_message_by_filename is used without
>> > > checking it for NULL.  Austin, can you comment on that at all?
>> >
>> > I'd be happy to distinguish these outcomes.  I did
>> > notmuch_database_find_message_by_filename the way I did only to be
>> > consistent with notmuch_database_find_message.  Since ndfmbf isn't
>> > entrenched yet, now is a good time to change it.
>>
>> What about notmuch_database_find_message()? If we leave it as it is,
>> this will lead to inconsistency and if we change it, we need to think
>> about API breakage issues.
>
>Yes.  We could just deal with that (there aren't *that* many API
>consumers).  For binary compatibility, I suppose we could even use
>symbol versioning.
>
>> > The call in notmuch-new should check the return, though if it can't
>> > find the message at that point, something has gone terribly wrong.
>> > Segfaulting is never the answer, though.
>>
>> Indeed, just not to step on each other's feet, are you going to write a
>> patch or shall I start writing one?
>
>Please feel free to write a patch.

Below is a quick patch, which compiles and passes tests.
Please comment.

         -alip

-- >8 --
Subject: [PATCH] lib: make find_message{,by_filename) report errors

Previously, the functions notmuch_database_find_message() and
notmuch_database_find_message_by_filename() functions did not properly
report error condition to the library user.

For more information, read the thread on the notmuch mailing list
starting with my mail "id:871uv2unfd.fsf@gmail.com"

Make these functions accept a pointer to 'notmuch_message_t' as argument
and return notmuch_status_t which may be used to check for any error
condition.

restore: Modify for the new notmuch_database_find_message()
new: Modify for the new notmuch_database_find_message_by_filename()
---
  lib/database.cc   |   89 ++++++++++++++++++++++++++++++++++------------------
  lib/message.cc    |    6 ++--
  lib/notmuch.h     |   61 +++++++++++++++++++++++++-----------
  notmuch-new.c     |    4 ++-
  notmuch-restore.c |   11 ++++--
  5 files changed, 114 insertions(+), 57 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 9299c8d..6641aa5 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -360,13 +360,17 @@ _message_id_compressed (void *ctx, const char *message_id)
      return compressed;
  }
  
-notmuch_message_t *
+notmuch_status_t
  notmuch_database_find_message (notmuch_database_t *notmuch,
-			       const char *message_id)
+			       const char *message_id,
+			       notmuch_message_t **message)
  {
      notmuch_private_status_t status;
      unsigned int doc_id;
  
+    if (message == NULL)
+	    return NOTMUCH_STATUS_NULL_POINTER;
+
      if (strlen (message_id) > NOTMUCH_MESSAGE_ID_MAX)
  	message_id = _message_id_compressed (notmuch, message_id);
  
@@ -375,14 +379,20 @@ notmuch_database_find_message (notmuch_database_t *notmuch,
  						       message_id, &doc_id);
  
  	if (status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND)
-	    return NULL;
+	    *message = NULL;
+	else {
+	    *message = _notmuch_message_create (notmuch, notmuch, doc_id, NULL);
+	    if (*message == NULL)
+		    return NOTMUCH_STATUS_OUT_OF_MEMORY;
+	}
  
-	return _notmuch_message_create (notmuch, notmuch, doc_id, NULL);
+	return NOTMUCH_STATUS_SUCCESS;
      } catch (const Xapian::Error &error) {
  	fprintf (stderr, "A Xapian exception occurred finding message: %s.\n",
  		 error.get_msg().c_str());
  	notmuch->exception_reported = TRUE;
-	return NULL;
+	*message = NULL;
+	return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
      }
  }
  
@@ -1311,7 +1321,8 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
  
  /* Find the thread ID to which the message with 'message_id' belongs.
   *
- * Always returns a newly talloced string belonging to 'ctx'.
+ * Note: 'thread_id' must not be NULL!
+ * On success '*thread_id' is set to a newly talloced string belonging to 'ctx'.
   *
   * Note: If there is no message in the database with the given
   * 'message_id' then a new thread_id will be allocated for this
@@ -1319,25 +1330,29 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
   * thread ID can be looked up if the message is added to the database
   * later).
   */
-static const char *
+static notmuch_status_t
  _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
  				  void *ctx,
-				  const char *message_id)
+				  const char *message_id,
+				  const char **thread_id)
  {
+    notmuch_status_t status;
      notmuch_message_t *message;
      string thread_id_string;
-    const char *thread_id;
      char *metadata_key;
      Xapian::WritableDatabase *db;
  
-    message = notmuch_database_find_message (notmuch, message_id);
+    status = notmuch_database_find_message (notmuch, message_id, &message);
+
+    if (status)
+	return status;
  
      if (message) {
-	thread_id = talloc_steal (ctx, notmuch_message_get_thread_id (message));
+	*thread_id = talloc_steal (ctx, notmuch_message_get_thread_id (message));
  
  	notmuch_message_destroy (message);
  
-	return thread_id;
+	return NOTMUCH_STATUS_SUCCESS;
      }
  
      /* Message has not been seen yet.
@@ -1351,15 +1366,15 @@ _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
      thread_id_string = notmuch->xapian_db->get_metadata (metadata_key);
  
      if (thread_id_string.empty()) {
-	thread_id = _notmuch_database_generate_thread_id (notmuch);
-	db->set_metadata (metadata_key, thread_id);
+	*thread_id = talloc_strdup(ctx, _notmuch_database_generate_thread_id (notmuch));
+	db->set_metadata (metadata_key, *thread_id);
      } else {
-	thread_id = thread_id_string.c_str();
+	*thread_id = talloc_strdup(ctx, thread_id_string.c_str());
      }
  
      talloc_free (metadata_key);
  
-    return talloc_strdup (ctx, thread_id);
+    return NOTMUCH_STATUS_SUCCESS;
  }
  
  static notmuch_status_t
@@ -1446,9 +1461,12 @@ _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch,
  	_notmuch_message_add_term (message, "reference",
  				   parent_message_id);
  
-	parent_thread_id = _resolve_message_id_to_thread_id (notmuch,
-							     message,
-							     parent_message_id);
+	ret = _resolve_message_id_to_thread_id (notmuch,
+						message,
+						parent_message_id,
+						&parent_thread_id);
+	if (ret)
+	    goto DONE;
  
  	if (*thread_id == NULL) {
  	    *thread_id = talloc_strdup (message, parent_thread_id);
@@ -1759,11 +1777,12 @@ notmuch_status_t
  notmuch_database_remove_message (notmuch_database_t *notmuch,
  				 const char *filename)
  {
-    notmuch_message_t *message =
-	notmuch_database_find_message_by_filename (notmuch, filename);
-    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+    notmuch_status_t status;
+    notmuch_message_t *message;
  
-    if (message) {
+    status = notmuch_database_find_message_by_filename (notmuch, filename, &message);
+
+    if (status == NOTMUCH_STATUS_SUCCESS && message) {
  	    status = _notmuch_message_remove_filename (message, filename);
  	    if (status == NOTMUCH_STATUS_SUCCESS)
  		_notmuch_message_delete (message);
@@ -1774,24 +1793,27 @@ notmuch_database_remove_message (notmuch_database_t *notmuch,
      return status;
  }
  
-notmuch_message_t *
+notmuch_status_t
  notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
-					   const char *filename)
+					   const char *filename,
+					   notmuch_message_t **message)
  {
      void *local;
      const char *prefix = _find_prefix ("file-direntry");
      char *direntry, *term;
      Xapian::PostingIterator i, end;
-    notmuch_message_t *message = NULL;
      notmuch_status_t status;
  
+    if (message == NULL)
+	    return NOTMUCH_STATUS_NULL_POINTER;
+
      local = talloc_new (notmuch);
  
      try {
  	status = _notmuch_database_filename_to_direntry (local, notmuch,
  							 filename, &direntry);
  	if (status)
-	    return NULL;
+	    goto DONE;
  
  	term = talloc_asprintf (local, "%s%s", prefix, direntry);
  
@@ -1800,19 +1822,24 @@ notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
  	if (i != end) {
  	    notmuch_private_status_t private_status;
  
-	    message = _notmuch_message_create (notmuch, notmuch,
-					       *i, &private_status);
+	    *message = _notmuch_message_create (notmuch, notmuch,
+					        *i, &private_status);
+	    if (*message == NULL)
+		    status = NOTMUCH_STATUS_OUT_OF_MEMORY;
  	}
      } catch (const Xapian::Error &error) {
  	fprintf (stderr, "Error: A Xapian exception occurred finding message by filename: %s\n",
  		 error.get_msg().c_str());
  	notmuch->exception_reported = TRUE;
-	message = NULL;
+	status = NOTMUCH_STATUS_OUT_OF_MEMORY;
      }
  
+  DONE:
      talloc_free (local);
  
-    return message;
+    if (status)
+	    *message = NULL;
+    return status;
  }
  
  notmuch_string_list_t *
diff --git a/lib/message.cc b/lib/message.cc
index 531d304..2a85744 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -216,11 +216,11 @@ _notmuch_message_create_for_message_id (notmuch_database_t *notmuch,
      unsigned int doc_id;
      char *term;
  
-    *status_ret = NOTMUCH_PRIVATE_STATUS_SUCCESS;
-
-    message = notmuch_database_find_message (notmuch, message_id);
+    *status_ret = (notmuch_private_status_t) notmuch_database_find_message (notmuch, message_id, &message);
      if (message)
  	return talloc_steal (notmuch, message);
+    else if (*status_ret)
+	return NULL;
  
      term = talloc_asprintf (NULL, "%s%s",
  			    _find_prefix ("id"), message_id);
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 6d7a99f..08b4ce2 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -347,35 +347,60 @@ notmuch_database_remove_message (notmuch_database_t *database,
  
  /* Find a message with the given message_id.
   *
- * If the database contains a message with the given message_id, then
- * a new notmuch_message_t object is returned. The caller should call
- * notmuch_message_destroy when done with the message.
+ * If message with the given message_id is found then, on successful return
+ * (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to a message object.
+ * The user should call notmuch_message_destroy when done with the message.
   *
- * This function returns NULL in the following situations:
+ * On any failure or when the message is not found, this function initializes
+ * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
+ * user is supposed to check '*message' for NULL to find out whether the
+ * message with the given message_id was found.
   *
- *	* No message is found with the given message_id
- *	* An out-of-memory situation occurs
- *	* A Xapian exception occurs
+ * Note: The argument 'message' must not be NULL!
+ *
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'.
+ *
+ * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
+ *
+ * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating message object
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
   */
-notmuch_message_t *
+notmuch_status_t
  notmuch_database_find_message (notmuch_database_t *database,
-			       const char *message_id);
+			       const char *message_id,
+			       notmuch_message_t **message);
  
  /* Find a message with the given filename.
   *
- * If the database contains a message with the given filename, then a
- * new notmuch_message_t object is returned.  The caller should call 
- * notmuch_message_destroy when done with the message.
+ * If the database contains a message with the given filename then, on
+ * successful return (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to
+ * a message object. The user should call notmuch_message_destroy when done
+ * with the message.
   *
- * This function returns NULL in the following situations:
+ * On any failure or when the message is not found, this function initializes
+ * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
+ * user is supposed to check '*message' for NULL to find out whether the
+ * message with the given filename is found.
   *
- *	* No message is found with the given filename
- *	* An out-of-memory situation occurs
- *	* A Xapian exception occurs
+ * Note: The argument 'message' must not be NULL!
+ *
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'
+ *
+ * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
+ *
+ * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating the message object
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
   */
-notmuch_message_t *
+notmuch_status_t
  notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
-					   const char *filename);
+					   const char *filename,
+					   notmuch_message_t **message);
  
  /* Return a list of all tags found in the database.
   *
diff --git a/notmuch-new.c b/notmuch-new.c
index e79593c..96a1e31 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -743,7 +743,9 @@ remove_filename (notmuch_database_t *notmuch,
      status = notmuch_database_begin_atomic (notmuch);
      if (status)
  	return status;
-    message = notmuch_database_find_message_by_filename (notmuch, path);
+    status = notmuch_database_find_message_by_filename (notmuch, path, &message);
+    if (status || message == NULL)
+	return status;
      status = notmuch_database_remove_message (notmuch, path);
      if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
  	add_files_state->renamed_messages++;
diff --git a/notmuch-restore.c b/notmuch-restore.c
index f095f64..3b0ae71 100644
--- a/notmuch-restore.c
+++ b/notmuch-restore.c
@@ -87,10 +87,13 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])
  	file_tags = xstrndup (line + match[2].rm_so,
  			      match[2].rm_eo - match[2].rm_so);
  
-	message = notmuch_database_find_message (notmuch, message_id);
-	if (message == NULL) {
-	    fprintf (stderr, "Warning: Cannot apply tags to missing message: %s\n",
-		     message_id);
+	status = notmuch_database_find_message (notmuch, message_id, &message);
+	if (status || message == NULL) {
+	    fprintf (stderr, "Warning: Cannot apply tags to %smessage: %s\n",
+		     message ? "" : "missing ", message_id);
+	    if (status)
+		    fprintf (stderr, "%s\n",
+			     notmuch_status_to_string(status));
  	    goto NEXT_LINE;
  	}
  
-- 
1.7.6.1

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH] lib: make find_message{,by_filename) report errors
  2011-09-30  6:47         ` Concerns regarding some library functions Ali Polatel
@ 2011-10-01  8:12           ` Ali Polatel
  2011-10-01  8:12             ` Ali Polatel
                               ` (2 more replies)
  0 siblings, 3 replies; 30+ messages in thread
From: Ali Polatel @ 2011-10-01  8:12 UTC (permalink / raw)
  To: Austin Clements; +Cc: Notmuch Mailing List, Ali Polatel

From: Ali Polatel <alip@exherbo.org>

Looks like the patch did not make it correctly the first time.
Resending using git-send-email™

You may also find the commit in my notmuch repository:
git://github.com/alip/notmuch.git branch: find_message

Ali Polatel (1):
  lib: make find_message{,by_filename) report errors

 lib/database.cc   |   89 ++++++++++++++++++++++++++++++++++------------------
 lib/message.cc    |    6 ++--
 lib/notmuch.h     |   61 +++++++++++++++++++++++++-----------
 notmuch-new.c     |    4 ++-
 notmuch-restore.c |   11 ++++--
 5 files changed, 114 insertions(+), 57 deletions(-)

-- 
1.7.6.1

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH] lib: make find_message{,by_filename) report errors
  2011-10-01  8:12           ` [PATCH] lib: make find_message{,by_filename) report errors Ali Polatel
@ 2011-10-01  8:12             ` Ali Polatel
  2011-10-05 13:42               ` Sebastian Spaeth
  2011-10-03 16:49             ` [PATCH v1 0/1] " Ali Polatel
  2011-10-04  1:10             ` [PATCH] lib: make find_message{,by_filename) report errors David Bremner
  2 siblings, 1 reply; 30+ messages in thread
From: Ali Polatel @ 2011-10-01  8:12 UTC (permalink / raw)
  To: Austin Clements; +Cc: Notmuch Mailing List

Previously, the functions notmuch_database_find_message() and
notmuch_database_find_message_by_filename() functions did not properly
report error condition to the library user.

For more information, read the thread on the notmuch mailing list
starting with my mail "id:871uv2unfd.fsf@gmail.com"

Make these functions accept a pointer to 'notmuch_message_t' as argument
and return notmuch_status_t which may be used to check for any error
condition.

restore: Modify for the new notmuch_database_find_message()
new: Modify for the new notmuch_database_find_message_by_filename()
---
 lib/database.cc   |   89 ++++++++++++++++++++++++++++++++++------------------
 lib/message.cc    |    6 ++--
 lib/notmuch.h     |   61 +++++++++++++++++++++++++-----------
 notmuch-new.c     |    4 ++-
 notmuch-restore.c |   11 ++++--
 5 files changed, 114 insertions(+), 57 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 9299c8d..6641aa5 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -360,13 +360,17 @@ _message_id_compressed (void *ctx, const char *message_id)
     return compressed;
 }
 
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message (notmuch_database_t *notmuch,
-			       const char *message_id)
+			       const char *message_id,
+			       notmuch_message_t **message)
 {
     notmuch_private_status_t status;
     unsigned int doc_id;
 
+    if (message == NULL)
+	    return NOTMUCH_STATUS_NULL_POINTER;
+
     if (strlen (message_id) > NOTMUCH_MESSAGE_ID_MAX)
 	message_id = _message_id_compressed (notmuch, message_id);
 
@@ -375,14 +379,20 @@ notmuch_database_find_message (notmuch_database_t *notmuch,
 						       message_id, &doc_id);
 
 	if (status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND)
-	    return NULL;
+	    *message = NULL;
+	else {
+	    *message = _notmuch_message_create (notmuch, notmuch, doc_id, NULL);
+	    if (*message == NULL)
+		    return NOTMUCH_STATUS_OUT_OF_MEMORY;
+	}
 
-	return _notmuch_message_create (notmuch, notmuch, doc_id, NULL);
+	return NOTMUCH_STATUS_SUCCESS;
     } catch (const Xapian::Error &error) {
 	fprintf (stderr, "A Xapian exception occurred finding message: %s.\n",
 		 error.get_msg().c_str());
 	notmuch->exception_reported = TRUE;
-	return NULL;
+	*message = NULL;
+	return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
     }
 }
 
@@ -1311,7 +1321,8 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
 
 /* Find the thread ID to which the message with 'message_id' belongs.
  *
- * Always returns a newly talloced string belonging to 'ctx'.
+ * Note: 'thread_id' must not be NULL!
+ * On success '*thread_id' is set to a newly talloced string belonging to 'ctx'.
  *
  * Note: If there is no message in the database with the given
  * 'message_id' then a new thread_id will be allocated for this
@@ -1319,25 +1330,29 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
  * thread ID can be looked up if the message is added to the database
  * later).
  */
-static const char *
+static notmuch_status_t
 _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
 				  void *ctx,
-				  const char *message_id)
+				  const char *message_id,
+				  const char **thread_id)
 {
+    notmuch_status_t status;
     notmuch_message_t *message;
     string thread_id_string;
-    const char *thread_id;
     char *metadata_key;
     Xapian::WritableDatabase *db;
 
-    message = notmuch_database_find_message (notmuch, message_id);
+    status = notmuch_database_find_message (notmuch, message_id, &message);
+
+    if (status)
+	return status;
 
     if (message) {
-	thread_id = talloc_steal (ctx, notmuch_message_get_thread_id (message));
+	*thread_id = talloc_steal (ctx, notmuch_message_get_thread_id (message));
 
 	notmuch_message_destroy (message);
 
-	return thread_id;
+	return NOTMUCH_STATUS_SUCCESS;
     }
 
     /* Message has not been seen yet.
@@ -1351,15 +1366,15 @@ _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
     thread_id_string = notmuch->xapian_db->get_metadata (metadata_key);
 
     if (thread_id_string.empty()) {
-	thread_id = _notmuch_database_generate_thread_id (notmuch);
-	db->set_metadata (metadata_key, thread_id);
+	*thread_id = talloc_strdup(ctx, _notmuch_database_generate_thread_id (notmuch));
+	db->set_metadata (metadata_key, *thread_id);
     } else {
-	thread_id = thread_id_string.c_str();
+	*thread_id = talloc_strdup(ctx, thread_id_string.c_str());
     }
 
     talloc_free (metadata_key);
 
-    return talloc_strdup (ctx, thread_id);
+    return NOTMUCH_STATUS_SUCCESS;
 }
 
 static notmuch_status_t
@@ -1446,9 +1461,12 @@ _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch,
 	_notmuch_message_add_term (message, "reference",
 				   parent_message_id);
 
-	parent_thread_id = _resolve_message_id_to_thread_id (notmuch,
-							     message,
-							     parent_message_id);
+	ret = _resolve_message_id_to_thread_id (notmuch,
+						message,
+						parent_message_id,
+						&parent_thread_id);
+	if (ret)
+	    goto DONE;
 
 	if (*thread_id == NULL) {
 	    *thread_id = talloc_strdup (message, parent_thread_id);
@@ -1759,11 +1777,12 @@ notmuch_status_t
 notmuch_database_remove_message (notmuch_database_t *notmuch,
 				 const char *filename)
 {
-    notmuch_message_t *message =
-	notmuch_database_find_message_by_filename (notmuch, filename);
-    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+    notmuch_status_t status;
+    notmuch_message_t *message;
 
-    if (message) {
+    status = notmuch_database_find_message_by_filename (notmuch, filename, &message);
+
+    if (status == NOTMUCH_STATUS_SUCCESS && message) {
 	    status = _notmuch_message_remove_filename (message, filename);
 	    if (status == NOTMUCH_STATUS_SUCCESS)
 		_notmuch_message_delete (message);
@@ -1774,24 +1793,27 @@ notmuch_database_remove_message (notmuch_database_t *notmuch,
     return status;
 }
 
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
-					   const char *filename)
+					   const char *filename,
+					   notmuch_message_t **message)
 {
     void *local;
     const char *prefix = _find_prefix ("file-direntry");
     char *direntry, *term;
     Xapian::PostingIterator i, end;
-    notmuch_message_t *message = NULL;
     notmuch_status_t status;
 
+    if (message == NULL)
+	    return NOTMUCH_STATUS_NULL_POINTER;
+
     local = talloc_new (notmuch);
 
     try {
 	status = _notmuch_database_filename_to_direntry (local, notmuch,
 							 filename, &direntry);
 	if (status)
-	    return NULL;
+	    goto DONE;
 
 	term = talloc_asprintf (local, "%s%s", prefix, direntry);
 
@@ -1800,19 +1822,24 @@ notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
 	if (i != end) {
 	    notmuch_private_status_t private_status;
 
-	    message = _notmuch_message_create (notmuch, notmuch,
-					       *i, &private_status);
+	    *message = _notmuch_message_create (notmuch, notmuch,
+					        *i, &private_status);
+	    if (*message == NULL)
+		    status = NOTMUCH_STATUS_OUT_OF_MEMORY;
 	}
     } catch (const Xapian::Error &error) {
 	fprintf (stderr, "Error: A Xapian exception occurred finding message by filename: %s\n",
 		 error.get_msg().c_str());
 	notmuch->exception_reported = TRUE;
-	message = NULL;
+	status = NOTMUCH_STATUS_OUT_OF_MEMORY;
     }
 
+  DONE:
     talloc_free (local);
 
-    return message;
+    if (status)
+	    *message = NULL;
+    return status;
 }
 
 notmuch_string_list_t *
diff --git a/lib/message.cc b/lib/message.cc
index 531d304..2a85744 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -216,11 +216,11 @@ _notmuch_message_create_for_message_id (notmuch_database_t *notmuch,
     unsigned int doc_id;
     char *term;
 
-    *status_ret = NOTMUCH_PRIVATE_STATUS_SUCCESS;
-
-    message = notmuch_database_find_message (notmuch, message_id);
+    *status_ret = (notmuch_private_status_t) notmuch_database_find_message (notmuch, message_id, &message);
     if (message)
 	return talloc_steal (notmuch, message);
+    else if (*status_ret)
+	return NULL;
 
     term = talloc_asprintf (NULL, "%s%s",
 			    _find_prefix ("id"), message_id);
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 6d7a99f..08b4ce2 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -347,35 +347,60 @@ notmuch_database_remove_message (notmuch_database_t *database,
 
 /* Find a message with the given message_id.
  *
- * If the database contains a message with the given message_id, then
- * a new notmuch_message_t object is returned. The caller should call
- * notmuch_message_destroy when done with the message.
+ * If message with the given message_id is found then, on successful return
+ * (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to a message object.
+ * The user should call notmuch_message_destroy when done with the message.
  *
- * This function returns NULL in the following situations:
+ * On any failure or when the message is not found, this function initializes
+ * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
+ * user is supposed to check '*message' for NULL to find out whether the
+ * message with the given message_id was found.
  *
- *	* No message is found with the given message_id
- *	* An out-of-memory situation occurs
- *	* A Xapian exception occurs
+ * Note: The argument 'message' must not be NULL!
+ *
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'.
+ *
+ * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
+ *
+ * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating message object
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
  */
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message (notmuch_database_t *database,
-			       const char *message_id);
+			       const char *message_id,
+			       notmuch_message_t **message);
 
 /* Find a message with the given filename.
  *
- * If the database contains a message with the given filename, then a
- * new notmuch_message_t object is returned.  The caller should call 
- * notmuch_message_destroy when done with the message.
+ * If the database contains a message with the given filename then, on
+ * successful return (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to
+ * a message object. The user should call notmuch_message_destroy when done
+ * with the message.
  *
- * This function returns NULL in the following situations:
+ * On any failure or when the message is not found, this function initializes
+ * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
+ * user is supposed to check '*message' for NULL to find out whether the
+ * message with the given filename is found.
  *
- *	* No message is found with the given filename
- *	* An out-of-memory situation occurs
- *	* A Xapian exception occurs
+ * Note: The argument 'message' must not be NULL!
+ *
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'
+ *
+ * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
+ *
+ * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating the message object
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
  */
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
-					   const char *filename);
+					   const char *filename,
+					   notmuch_message_t **message);
 
 /* Return a list of all tags found in the database.
  *
diff --git a/notmuch-new.c b/notmuch-new.c
index e79593c..96a1e31 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -743,7 +743,9 @@ remove_filename (notmuch_database_t *notmuch,
     status = notmuch_database_begin_atomic (notmuch);
     if (status)
 	return status;
-    message = notmuch_database_find_message_by_filename (notmuch, path);
+    status = notmuch_database_find_message_by_filename (notmuch, path, &message);
+    if (status || message == NULL)
+	return status;
     status = notmuch_database_remove_message (notmuch, path);
     if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
 	add_files_state->renamed_messages++;
diff --git a/notmuch-restore.c b/notmuch-restore.c
index f095f64..3b0ae71 100644
--- a/notmuch-restore.c
+++ b/notmuch-restore.c
@@ -87,10 +87,13 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])
 	file_tags = xstrndup (line + match[2].rm_so,
 			      match[2].rm_eo - match[2].rm_so);
 
-	message = notmuch_database_find_message (notmuch, message_id);
-	if (message == NULL) {
-	    fprintf (stderr, "Warning: Cannot apply tags to missing message: %s\n",
-		     message_id);
+	status = notmuch_database_find_message (notmuch, message_id, &message);
+	if (status || message == NULL) {
+	    fprintf (stderr, "Warning: Cannot apply tags to %smessage: %s\n",
+		     message ? "" : "missing ", message_id);
+	    if (status)
+		    fprintf (stderr, "%s\n",
+			     notmuch_status_to_string(status));
 	    goto NEXT_LINE;
 	}
 
-- 
1.7.6.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v1 0/1] lib: make find_message{,by_filename) report errors
  2011-10-01  8:12           ` [PATCH] lib: make find_message{,by_filename) report errors Ali Polatel
  2011-10-01  8:12             ` Ali Polatel
@ 2011-10-03 16:49             ` Ali Polatel
  2011-10-03 16:49               ` [PATCH v1 1/1] " Ali Polatel
  2011-10-04  1:10             ` [PATCH] lib: make find_message{,by_filename) report errors David Bremner
  2 siblings, 1 reply; 30+ messages in thread
From: Ali Polatel @ 2011-10-03 16:49 UTC (permalink / raw)
  To: Notmuch Mailing List; +Cc: Austin Clements

Here is an updated patch fixing style issues addressed by amdragon on
IRC. I plan to submit a patch documenting how to configure VIM to code
using notmuch's style guidelines as well.

You may also find the commit in my notmuch repository:
git://github.com/alip/notmuch.git branch: find_message-v1

Ali Polatel (1):
  lib: make find_message{,by_filename) report errors

 lib/database.cc   |   90 ++++++++++++++++++++++++++++++++++------------------
 lib/message.cc    |    6 ++--
 lib/notmuch.h     |   61 +++++++++++++++++++++++++----------
 notmuch-new.c     |    4 ++-
 notmuch-restore.c |   11 ++++--
 5 files changed, 115 insertions(+), 57 deletions(-)

-- 
1.7.6.1

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v1 1/1] lib: make find_message{,by_filename) report errors
  2011-10-03 16:49             ` [PATCH v1 0/1] " Ali Polatel
@ 2011-10-03 16:49               ` Ali Polatel
  2011-10-03 17:43                 ` Austin Clements
  0 siblings, 1 reply; 30+ messages in thread
From: Ali Polatel @ 2011-10-03 16:49 UTC (permalink / raw)
  To: Notmuch Mailing List; +Cc: Austin Clements

Previously, the functions notmuch_database_find_message() and
notmuch_database_find_message_by_filename() functions did not properly
report error condition to the library user.

For more information, read the thread on the notmuch mailing list
starting with my mail "id:871uv2unfd.fsf@gmail.com"

Make these functions accept a pointer to 'notmuch_message_t' as argument
and return notmuch_status_t which may be used to check for any error
condition.

restore: Modify for the new notmuch_database_find_message()
new: Modify for the new notmuch_database_find_message_by_filename()
---
 lib/database.cc   |   90 ++++++++++++++++++++++++++++++++++------------------
 lib/message.cc    |    6 ++--
 lib/notmuch.h     |   61 +++++++++++++++++++++++++----------
 notmuch-new.c     |    4 ++-
 notmuch-restore.c |   11 ++++--
 5 files changed, 115 insertions(+), 57 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 9299c8d..1705232 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -360,13 +360,17 @@ _message_id_compressed (void *ctx, const char *message_id)
     return compressed;
 }
 
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message (notmuch_database_t *notmuch,
-			       const char *message_id)
+			       const char *message_id,
+			       notmuch_message_t **message)
 {
     notmuch_private_status_t status;
     unsigned int doc_id;
 
+    if (message == NULL)
+	return NOTMUCH_STATUS_NULL_POINTER;
+
     if (strlen (message_id) > NOTMUCH_MESSAGE_ID_MAX)
 	message_id = _message_id_compressed (notmuch, message_id);
 
@@ -375,14 +379,21 @@ notmuch_database_find_message (notmuch_database_t *notmuch,
 						       message_id, &doc_id);
 
 	if (status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND)
-	    return NULL;
+	    *message = NULL;
+	else {
+	    *message = _notmuch_message_create (notmuch, notmuch, doc_id,
+						NULL);
+	    if (*message == NULL)
+		return NOTMUCH_STATUS_OUT_OF_MEMORY;
+	}
 
-	return _notmuch_message_create (notmuch, notmuch, doc_id, NULL);
+	return NOTMUCH_STATUS_SUCCESS;
     } catch (const Xapian::Error &error) {
 	fprintf (stderr, "A Xapian exception occurred finding message: %s.\n",
 		 error.get_msg().c_str());
 	notmuch->exception_reported = TRUE;
-	return NULL;
+	*message = NULL;
+	return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
     }
 }
 
@@ -1311,7 +1322,8 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
 
 /* Find the thread ID to which the message with 'message_id' belongs.
  *
- * Always returns a newly talloced string belonging to 'ctx'.
+ * Note: 'thread_id' must not be NULL!
+ * On success '*thread_id' is set to a newly talloced string belonging to 'ctx'.
  *
  * Note: If there is no message in the database with the given
  * 'message_id' then a new thread_id will be allocated for this
@@ -1319,25 +1331,29 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
  * thread ID can be looked up if the message is added to the database
  * later).
  */
-static const char *
+static notmuch_status_t
 _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
 				  void *ctx,
-				  const char *message_id)
+				  const char *message_id,
+				  const char **thread_id)
 {
+    notmuch_status_t status;
     notmuch_message_t *message;
     string thread_id_string;
-    const char *thread_id;
     char *metadata_key;
     Xapian::WritableDatabase *db;
 
-    message = notmuch_database_find_message (notmuch, message_id);
+    status = notmuch_database_find_message (notmuch, message_id, &message);
+
+    if (status)
+	return status;
 
     if (message) {
-	thread_id = talloc_steal (ctx, notmuch_message_get_thread_id (message));
+	*thread_id = talloc_steal (ctx, notmuch_message_get_thread_id (message));
 
 	notmuch_message_destroy (message);
 
-	return thread_id;
+	return NOTMUCH_STATUS_SUCCESS;
     }
 
     /* Message has not been seen yet.
@@ -1351,15 +1367,15 @@ _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
     thread_id_string = notmuch->xapian_db->get_metadata (metadata_key);
 
     if (thread_id_string.empty()) {
-	thread_id = _notmuch_database_generate_thread_id (notmuch);
-	db->set_metadata (metadata_key, thread_id);
+	*thread_id = talloc_strdup (ctx, _notmuch_database_generate_thread_id (notmuch));
+	db->set_metadata (metadata_key, *thread_id);
     } else {
-	thread_id = thread_id_string.c_str();
+	*thread_id = talloc_strdup(ctx, thread_id_string.c_str());
     }
 
     talloc_free (metadata_key);
 
-    return talloc_strdup (ctx, thread_id);
+    return NOTMUCH_STATUS_SUCCESS;
 }
 
 static notmuch_status_t
@@ -1446,9 +1462,12 @@ _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch,
 	_notmuch_message_add_term (message, "reference",
 				   parent_message_id);
 
-	parent_thread_id = _resolve_message_id_to_thread_id (notmuch,
-							     message,
-							     parent_message_id);
+	ret = _resolve_message_id_to_thread_id (notmuch,
+						message,
+						parent_message_id,
+						&parent_thread_id);
+	if (ret)
+	    goto DONE;
 
 	if (*thread_id == NULL) {
 	    *thread_id = talloc_strdup (message, parent_thread_id);
@@ -1759,11 +1778,12 @@ notmuch_status_t
 notmuch_database_remove_message (notmuch_database_t *notmuch,
 				 const char *filename)
 {
-    notmuch_message_t *message =
-	notmuch_database_find_message_by_filename (notmuch, filename);
-    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+    notmuch_status_t status;
+    notmuch_message_t *message;
 
-    if (message) {
+    status = notmuch_database_find_message_by_filename (notmuch, filename, &message);
+
+    if (status == NOTMUCH_STATUS_SUCCESS && message) {
 	    status = _notmuch_message_remove_filename (message, filename);
 	    if (status == NOTMUCH_STATUS_SUCCESS)
 		_notmuch_message_delete (message);
@@ -1774,24 +1794,27 @@ notmuch_database_remove_message (notmuch_database_t *notmuch,
     return status;
 }
 
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
-					   const char *filename)
+					   const char *filename,
+					   notmuch_message_t **message)
 {
     void *local;
     const char *prefix = _find_prefix ("file-direntry");
     char *direntry, *term;
     Xapian::PostingIterator i, end;
-    notmuch_message_t *message = NULL;
     notmuch_status_t status;
 
+    if (message == NULL)
+	return NOTMUCH_STATUS_NULL_POINTER;
+
     local = talloc_new (notmuch);
 
     try {
 	status = _notmuch_database_filename_to_direntry (local, notmuch,
 							 filename, &direntry);
 	if (status)
-	    return NULL;
+	    goto DONE;
 
 	term = talloc_asprintf (local, "%s%s", prefix, direntry);
 
@@ -1800,19 +1823,24 @@ notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
 	if (i != end) {
 	    notmuch_private_status_t private_status;
 
-	    message = _notmuch_message_create (notmuch, notmuch,
-					       *i, &private_status);
+	    *message = _notmuch_message_create (notmuch, notmuch,
+						*i, &private_status);
+	    if (*message == NULL)
+		status = NOTMUCH_STATUS_OUT_OF_MEMORY;
 	}
     } catch (const Xapian::Error &error) {
 	fprintf (stderr, "Error: A Xapian exception occurred finding message by filename: %s\n",
 		 error.get_msg().c_str());
 	notmuch->exception_reported = TRUE;
-	message = NULL;
+	status = NOTMUCH_STATUS_OUT_OF_MEMORY;
     }
 
+  DONE:
     talloc_free (local);
 
-    return message;
+    if (status)
+	*message = NULL;
+    return status;
 }
 
 notmuch_string_list_t *
diff --git a/lib/message.cc b/lib/message.cc
index 531d304..2a85744 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -216,11 +216,11 @@ _notmuch_message_create_for_message_id (notmuch_database_t *notmuch,
     unsigned int doc_id;
     char *term;
 
-    *status_ret = NOTMUCH_PRIVATE_STATUS_SUCCESS;
-
-    message = notmuch_database_find_message (notmuch, message_id);
+    *status_ret = (notmuch_private_status_t) notmuch_database_find_message (notmuch, message_id, &message);
     if (message)
 	return talloc_steal (notmuch, message);
+    else if (*status_ret)
+	return NULL;
 
     term = talloc_asprintf (NULL, "%s%s",
 			    _find_prefix ("id"), message_id);
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 6d7a99f..08b4ce2 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -347,35 +347,60 @@ notmuch_database_remove_message (notmuch_database_t *database,
 
 /* Find a message with the given message_id.
  *
- * If the database contains a message with the given message_id, then
- * a new notmuch_message_t object is returned. The caller should call
- * notmuch_message_destroy when done with the message.
+ * If message with the given message_id is found then, on successful return
+ * (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to a message object.
+ * The user should call notmuch_message_destroy when done with the message.
  *
- * This function returns NULL in the following situations:
+ * On any failure or when the message is not found, this function initializes
+ * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
+ * user is supposed to check '*message' for NULL to find out whether the
+ * message with the given message_id was found.
  *
- *	* No message is found with the given message_id
- *	* An out-of-memory situation occurs
- *	* A Xapian exception occurs
+ * Note: The argument 'message' must not be NULL!
+ *
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'.
+ *
+ * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
+ *
+ * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating message object
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
  */
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message (notmuch_database_t *database,
-			       const char *message_id);
+			       const char *message_id,
+			       notmuch_message_t **message);
 
 /* Find a message with the given filename.
  *
- * If the database contains a message with the given filename, then a
- * new notmuch_message_t object is returned.  The caller should call 
- * notmuch_message_destroy when done with the message.
+ * If the database contains a message with the given filename then, on
+ * successful return (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to
+ * a message object. The user should call notmuch_message_destroy when done
+ * with the message.
  *
- * This function returns NULL in the following situations:
+ * On any failure or when the message is not found, this function initializes
+ * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
+ * user is supposed to check '*message' for NULL to find out whether the
+ * message with the given filename is found.
  *
- *	* No message is found with the given filename
- *	* An out-of-memory situation occurs
- *	* A Xapian exception occurs
+ * Note: The argument 'message' must not be NULL!
+ *
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'
+ *
+ * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
+ *
+ * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating the message object
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
  */
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
-					   const char *filename);
+					   const char *filename,
+					   notmuch_message_t **message);
 
 /* Return a list of all tags found in the database.
  *
diff --git a/notmuch-new.c b/notmuch-new.c
index e79593c..96a1e31 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -743,7 +743,9 @@ remove_filename (notmuch_database_t *notmuch,
     status = notmuch_database_begin_atomic (notmuch);
     if (status)
 	return status;
-    message = notmuch_database_find_message_by_filename (notmuch, path);
+    status = notmuch_database_find_message_by_filename (notmuch, path, &message);
+    if (status || message == NULL)
+	return status;
     status = notmuch_database_remove_message (notmuch, path);
     if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
 	add_files_state->renamed_messages++;
diff --git a/notmuch-restore.c b/notmuch-restore.c
index f095f64..e4a5355 100644
--- a/notmuch-restore.c
+++ b/notmuch-restore.c
@@ -87,10 +87,13 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])
 	file_tags = xstrndup (line + match[2].rm_so,
 			      match[2].rm_eo - match[2].rm_so);
 
-	message = notmuch_database_find_message (notmuch, message_id);
-	if (message == NULL) {
-	    fprintf (stderr, "Warning: Cannot apply tags to missing message: %s\n",
-		     message_id);
+	status = notmuch_database_find_message (notmuch, message_id, &message);
+	if (status || message == NULL) {
+	    fprintf (stderr, "Warning: Cannot apply tags to %smessage: %s\n",
+		     message ? "" : "missing ", message_id);
+	    if (status)
+		fprintf (stderr, "%s\n",
+			 notmuch_status_to_string(status));
 	    goto NEXT_LINE;
 	}
 
-- 
1.7.6.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 1/1] lib: make find_message{,by_filename) report errors
  2011-10-03 16:49               ` [PATCH v1 1/1] " Ali Polatel
@ 2011-10-03 17:43                 ` Austin Clements
  2011-10-03 20:38                   ` [PATCH v1 1/1] lib: make find_message{, by_filename) " Ali Polatel
  0 siblings, 1 reply; 30+ messages in thread
From: Austin Clements @ 2011-10-03 17:43 UTC (permalink / raw)
  To: Ali Polatel; +Cc: Notmuch Mailing List

All of the code looks good to me (and improving error handling is
always a good thing).  Some style nits are inline below.

The changes to _resolve_message_id_to_thread_id and
_notmuch_database_link_message_to_parents seem like just plain better
error handling and unrelated to the find_message API changes.  Perhaps
these should be in a separate patch?

Quoth Ali Polatel on Oct 03 at  7:49 pm:
> Previously, the functions notmuch_database_find_message() and
> notmuch_database_find_message_by_filename() functions did not properly
> report error condition to the library user.
> 
> For more information, read the thread on the notmuch mailing list
> starting with my mail "id:871uv2unfd.fsf@gmail.com"
> 
> Make these functions accept a pointer to 'notmuch_message_t' as argument
> and return notmuch_status_t which may be used to check for any error
> condition.
> 
> restore: Modify for the new notmuch_database_find_message()
> new: Modify for the new notmuch_database_find_message_by_filename()
> ---
>  lib/database.cc   |   90 ++++++++++++++++++++++++++++++++++------------------
>  lib/message.cc    |    6 ++--
>  lib/notmuch.h     |   61 +++++++++++++++++++++++++----------
>  notmuch-new.c     |    4 ++-
>  notmuch-restore.c |   11 ++++--
>  5 files changed, 115 insertions(+), 57 deletions(-)
> 
> diff --git a/lib/database.cc b/lib/database.cc
> index 9299c8d..1705232 100644
> --- a/lib/database.cc
> +++ b/lib/database.cc
> @@ -360,13 +360,17 @@ _message_id_compressed (void *ctx, const char *message_id)
>      return compressed;
>  }
>  
> -notmuch_message_t *
> +notmuch_status_t
>  notmuch_database_find_message (notmuch_database_t *notmuch,
> -			       const char *message_id)
> +			       const char *message_id,
> +			       notmuch_message_t **message)

Perhaps this should be message_ret to clearly distinguish it as an
out-argument?

>  {
>      notmuch_private_status_t status;
>      unsigned int doc_id;
>  
> +    if (message == NULL)
> +	return NOTMUCH_STATUS_NULL_POINTER;
> +
>      if (strlen (message_id) > NOTMUCH_MESSAGE_ID_MAX)
>  	message_id = _message_id_compressed (notmuch, message_id);
>  
> @@ -375,14 +379,21 @@ notmuch_database_find_message (notmuch_database_t *notmuch,
>  						       message_id, &doc_id);
>  
>  	if (status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND)
> -	    return NULL;
> +	    *message = NULL;
> +	else {
> +	    *message = _notmuch_message_create (notmuch, notmuch, doc_id,
> +						NULL);
> +	    if (*message == NULL)
> +		return NOTMUCH_STATUS_OUT_OF_MEMORY;
> +	}
>  
> -	return _notmuch_message_create (notmuch, notmuch, doc_id, NULL);
> +	return NOTMUCH_STATUS_SUCCESS;
>      } catch (const Xapian::Error &error) {
>  	fprintf (stderr, "A Xapian exception occurred finding message: %s.\n",
>  		 error.get_msg().c_str());
>  	notmuch->exception_reported = TRUE;
> -	return NULL;
> +	*message = NULL;
> +	return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
>      }
>  }
>  
> @@ -1311,7 +1322,8 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
>  
>  /* Find the thread ID to which the message with 'message_id' belongs.
>   *
> - * Always returns a newly talloced string belonging to 'ctx'.
> + * Note: 'thread_id' must not be NULL!
> + * On success '*thread_id' is set to a newly talloced string belonging to 'ctx'.
>   *
>   * Note: If there is no message in the database with the given
>   * 'message_id' then a new thread_id will be allocated for this
> @@ -1319,25 +1331,29 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
>   * thread ID can be looked up if the message is added to the database
>   * later).
>   */
> -static const char *
> +static notmuch_status_t
>  _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
>  				  void *ctx,
> -				  const char *message_id)
> +				  const char *message_id,
> +				  const char **thread_id)

thread_id_ret?

>  {
> +    notmuch_status_t status;
>      notmuch_message_t *message;
>      string thread_id_string;
> -    const char *thread_id;
>      char *metadata_key;
>      Xapian::WritableDatabase *db;
>  
> -    message = notmuch_database_find_message (notmuch, message_id);
> +    status = notmuch_database_find_message (notmuch, message_id, &message);
> +
> +    if (status)
> +	return status;
>  
>      if (message) {
> -	thread_id = talloc_steal (ctx, notmuch_message_get_thread_id (message));
> +	*thread_id = talloc_steal (ctx, notmuch_message_get_thread_id (message));
>  
>  	notmuch_message_destroy (message);
>  
> -	return thread_id;
> +	return NOTMUCH_STATUS_SUCCESS;
>      }
>  
>      /* Message has not been seen yet.
> @@ -1351,15 +1367,15 @@ _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
>      thread_id_string = notmuch->xapian_db->get_metadata (metadata_key);
>  
>      if (thread_id_string.empty()) {
> -	thread_id = _notmuch_database_generate_thread_id (notmuch);
> -	db->set_metadata (metadata_key, thread_id);
> +	*thread_id = talloc_strdup (ctx, _notmuch_database_generate_thread_id (notmuch));
> +	db->set_metadata (metadata_key, *thread_id);
>      } else {
> -	thread_id = thread_id_string.c_str();
> +	*thread_id = talloc_strdup(ctx, thread_id_string.c_str());

Missing space after talloc_strdup.

>      }
>  
>      talloc_free (metadata_key);
>  
> -    return talloc_strdup (ctx, thread_id);
> +    return NOTMUCH_STATUS_SUCCESS;
>  }
>  
>  static notmuch_status_t
> @@ -1446,9 +1462,12 @@ _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch,
>  	_notmuch_message_add_term (message, "reference",
>  				   parent_message_id);
>  
> -	parent_thread_id = _resolve_message_id_to_thread_id (notmuch,
> -							     message,
> -							     parent_message_id);
> +	ret = _resolve_message_id_to_thread_id (notmuch,
> +						message,
> +						parent_message_id,
> +						&parent_thread_id);
> +	if (ret)
> +	    goto DONE;
>  
>  	if (*thread_id == NULL) {
>  	    *thread_id = talloc_strdup (message, parent_thread_id);
> @@ -1759,11 +1778,12 @@ notmuch_status_t
>  notmuch_database_remove_message (notmuch_database_t *notmuch,
>  				 const char *filename)
>  {
> -    notmuch_message_t *message =
> -	notmuch_database_find_message_by_filename (notmuch, filename);
> -    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
> +    notmuch_status_t status;
> +    notmuch_message_t *message;
>  
> -    if (message) {
> +    status = notmuch_database_find_message_by_filename (notmuch, filename, &message);
> +
> +    if (status == NOTMUCH_STATUS_SUCCESS && message) {
>  	    status = _notmuch_message_remove_filename (message, filename);
>  	    if (status == NOTMUCH_STATUS_SUCCESS)
>  		_notmuch_message_delete (message);

This isn't a problem with your patch, but shouldn't this function be
notmuch_message_destroy'ing message?

> @@ -1774,24 +1794,27 @@ notmuch_database_remove_message (notmuch_database_t *notmuch,
>      return status;
>  }
>  
> -notmuch_message_t *
> +notmuch_status_t
>  notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
> -					   const char *filename)
> +					   const char *filename,
> +					   notmuch_message_t **message)

message_ret?

>  {
>      void *local;
>      const char *prefix = _find_prefix ("file-direntry");
>      char *direntry, *term;
>      Xapian::PostingIterator i, end;
> -    notmuch_message_t *message = NULL;
>      notmuch_status_t status;
>  
> +    if (message == NULL)
> +	return NOTMUCH_STATUS_NULL_POINTER;
> +
>      local = talloc_new (notmuch);
>  
>      try {
>  	status = _notmuch_database_filename_to_direntry (local, notmuch,
>  							 filename, &direntry);
>  	if (status)
> -	    return NULL;
> +	    goto DONE;
>  
>  	term = talloc_asprintf (local, "%s%s", prefix, direntry);
>  
> @@ -1800,19 +1823,24 @@ notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
>  	if (i != end) {
>  	    notmuch_private_status_t private_status;
>  
> -	    message = _notmuch_message_create (notmuch, notmuch,
> -					       *i, &private_status);
> +	    *message = _notmuch_message_create (notmuch, notmuch,
> +						*i, &private_status);
> +	    if (*message == NULL)
> +		status = NOTMUCH_STATUS_OUT_OF_MEMORY;
>  	}
>      } catch (const Xapian::Error &error) {
>  	fprintf (stderr, "Error: A Xapian exception occurred finding message by filename: %s\n",
>  		 error.get_msg().c_str());
>  	notmuch->exception_reported = TRUE;
> -	message = NULL;
> +	status = NOTMUCH_STATUS_OUT_OF_MEMORY;
>      }
>  
> +  DONE:
>      talloc_free (local);
>  
> -    return message;
> +    if (status)
> +	*message = NULL;
> +    return status;
>  }
>  
>  notmuch_string_list_t *
> diff --git a/lib/message.cc b/lib/message.cc
> index 531d304..2a85744 100644
> --- a/lib/message.cc
> +++ b/lib/message.cc
> @@ -216,11 +216,11 @@ _notmuch_message_create_for_message_id (notmuch_database_t *notmuch,
>      unsigned int doc_id;
>      char *term;
>  
> -    *status_ret = NOTMUCH_PRIVATE_STATUS_SUCCESS;
> -
> -    message = notmuch_database_find_message (notmuch, message_id);
> +    *status_ret = (notmuch_private_status_t) notmuch_database_find_message (notmuch, message_id, &message);

Long line, should probably be wrapped.

>      if (message)
>  	return talloc_steal (notmuch, message);
> +    else if (*status_ret)
> +	return NULL;
>  
>      term = talloc_asprintf (NULL, "%s%s",
>  			    _find_prefix ("id"), message_id);
> diff --git a/lib/notmuch.h b/lib/notmuch.h
> index 6d7a99f..08b4ce2 100644
> --- a/lib/notmuch.h
> +++ b/lib/notmuch.h
> @@ -347,35 +347,60 @@ notmuch_database_remove_message (notmuch_database_t *database,
>  
>  /* Find a message with the given message_id.
>   *
> - * If the database contains a message with the given message_id, then
> - * a new notmuch_message_t object is returned. The caller should call
> - * notmuch_message_destroy when done with the message.
> + * If message with the given message_id is found then, on successful return

"If a message"

> + * (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to a message object.
> + * The user should call notmuch_message_destroy when done with the message.

Probably s/user/caller/, since "the user" is the person sitting at the
keyboard.  (notmuch.h isn't very good about this, but it does use
"caller" more often than "user").

> - * This function returns NULL in the following situations:
> + * On any failure or when the message is not found, this function initializes
> + * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
> + * user is supposed to check '*message' for NULL to find out whether the
> + * message with the given message_id was found.
>   *
> - *	* No message is found with the given message_id
> - *	* An out-of-memory situation occurs
> - *	* A Xapian exception occurs
> + * Note: The argument 'message' must not be NULL!

Since it's clearly specified what happens if 'message' is NULL, this
note isn't necessary.

> + *
> + * Return value:
> + *
> + * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'.
> + *
> + * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
> + *
> + * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating message object
> + *
> + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
>   */
> -notmuch_message_t *
> +notmuch_status_t
>  notmuch_database_find_message (notmuch_database_t *database,
> -			       const char *message_id);
> +			       const char *message_id,
> +			       notmuch_message_t **message);
>  
>  /* Find a message with the given filename.
>   *
> - * If the database contains a message with the given filename, then a
> - * new notmuch_message_t object is returned.  The caller should call 
> - * notmuch_message_destroy when done with the message.
> + * If the database contains a message with the given filename then, on
> + * successful return (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to
> + * a message object. The user should call notmuch_message_destroy when done
> + * with the message.

Same comment about "user" as above.

>   *
> - * This function returns NULL in the following situations:
> + * On any failure or when the message is not found, this function initializes
> + * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
> + * user is supposed to check '*message' for NULL to find out whether the
> + * message with the given filename is found.
>   *
> - *	* No message is found with the given filename
> - *	* An out-of-memory situation occurs
> - *	* A Xapian exception occurs
> + * Note: The argument 'message' must not be NULL!

Same comment about this note as above.

> + *
> + * Return value:
> + *
> + * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'
> + *
> + * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
> + *
> + * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating the message object
> + *
> + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
>   */
> -notmuch_message_t *
> +notmuch_status_t
>  notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
> -					   const char *filename);
> +					   const char *filename,
> +					   notmuch_message_t **message);
>  
>  /* Return a list of all tags found in the database.
>   *
> diff --git a/notmuch-new.c b/notmuch-new.c
> index e79593c..96a1e31 100644
> --- a/notmuch-new.c
> +++ b/notmuch-new.c
> @@ -743,7 +743,9 @@ remove_filename (notmuch_database_t *notmuch,
>      status = notmuch_database_begin_atomic (notmuch);
>      if (status)
>  	return status;
> -    message = notmuch_database_find_message_by_filename (notmuch, path);
> +    status = notmuch_database_find_message_by_filename (notmuch, path, &message);
> +    if (status || message == NULL)
> +	return status;
>      status = notmuch_database_remove_message (notmuch, path);
>      if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
>  	add_files_state->renamed_messages++;
> diff --git a/notmuch-restore.c b/notmuch-restore.c
> index f095f64..e4a5355 100644
> --- a/notmuch-restore.c
> +++ b/notmuch-restore.c
> @@ -87,10 +87,13 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])
>  	file_tags = xstrndup (line + match[2].rm_so,
>  			      match[2].rm_eo - match[2].rm_so);
>  
> -	message = notmuch_database_find_message (notmuch, message_id);
> -	if (message == NULL) {
> -	    fprintf (stderr, "Warning: Cannot apply tags to missing message: %s\n",
> -		     message_id);
> +	status = notmuch_database_find_message (notmuch, message_id, &message);
> +	if (status || message == NULL) {
> +	    fprintf (stderr, "Warning: Cannot apply tags to %smessage: %s\n",
> +		     message ? "" : "missing ", message_id);
> +	    if (status)
> +		fprintf (stderr, "%s\n",
> +			 notmuch_status_to_string(status));
>  	    goto NEXT_LINE;
>  	}
>  

-- 
Austin Clements                                      MIT/'06/PhD/CSAIL
amdragon@mit.edu                           http://web.mit.edu/amdragon
       Somewhere in the dream we call reality you will find me,
              searching for the reality we call dreams.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v1 1/1] lib: make find_message{, by_filename) report errors
  2011-10-03 17:43                 ` Austin Clements
@ 2011-10-03 20:38                   ` Ali Polatel
  2011-10-03 20:40                     ` [PATCH v2 0/2] Better error handling Ali Polatel
  0 siblings, 1 reply; 30+ messages in thread
From: Ali Polatel @ 2011-10-03 20:38 UTC (permalink / raw)
  To: Austin Clements; +Cc: Notmuch Mailing List

[-- Attachment #1: Type: text/plain, Size: 16794 bytes --]

Austin Clements yazmış:
>All of the code looks good to me (and improving error handling is
>always a good thing).  Some style nits are inline below.

Thanks for the review, comments below and a new set of patches follow...

>The changes to _resolve_message_id_to_thread_id and
>_notmuch_database_link_message_to_parents seem like just plain better
>error handling and unrelated to the find_message API changes.  Perhaps
>these should be in a separate patch?

I don't think this is wise considering the fact that the prototypes of
the functions change. Separating this into two patches will leave the
state of the tree broken between the two patches which is bad for
git-bisect. In addition, considering the small size and compactness of
the patch, I don't think it's worth the effort.

>Quoth Ali Polatel on Oct 03 at  7:49 pm:
>> Previously, the functions notmuch_database_find_message() and
>> notmuch_database_find_message_by_filename() functions did not properly
>> report error condition to the library user.
>>
>> For more information, read the thread on the notmuch mailing list
>> starting with my mail "id:871uv2unfd.fsf@gmail.com"
>>
>> Make these functions accept a pointer to 'notmuch_message_t' as argument
>> and return notmuch_status_t which may be used to check for any error
>> condition.
>>
>> restore: Modify for the new notmuch_database_find_message()
>> new: Modify for the new notmuch_database_find_message_by_filename()
>> ---
>>  lib/database.cc   |   90 ++++++++++++++++++++++++++++++++++------------------
>>  lib/message.cc    |    6 ++--
>>  lib/notmuch.h     |   61 +++++++++++++++++++++++++----------
>>  notmuch-new.c     |    4 ++-
>>  notmuch-restore.c |   11 ++++--
>>  5 files changed, 115 insertions(+), 57 deletions(-)
>>
>> diff --git a/lib/database.cc b/lib/database.cc
>> index 9299c8d..1705232 100644
>> --- a/lib/database.cc
>> +++ b/lib/database.cc
>> @@ -360,13 +360,17 @@ _message_id_compressed (void *ctx, const char *message_id)
>>      return compressed;
>>  }
>>
>> -notmuch_message_t *
>> +notmuch_status_t
>>  notmuch_database_find_message (notmuch_database_t *notmuch,
>> -			       const char *message_id)
>> +			       const char *message_id,
>> +			       notmuch_message_t **message)
>
>Perhaps this should be message_ret to clearly distinguish it as an
>out-argument?

This crossed my mind while working on the initial patch but I guess I
was just being lazy. Fixed.

>>  {
>>      notmuch_private_status_t status;
>>      unsigned int doc_id;
>>
>> +    if (message == NULL)
>> +	return NOTMUCH_STATUS_NULL_POINTER;
>> +
>>      if (strlen (message_id) > NOTMUCH_MESSAGE_ID_MAX)
>>  	message_id = _message_id_compressed (notmuch, message_id);
>>
>> @@ -375,14 +379,21 @@ notmuch_database_find_message (notmuch_database_t *notmuch,
>>  						       message_id, &doc_id);
>>
>>  	if (status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND)
>> -	    return NULL;
>> +	    *message = NULL;
>> +	else {
>> +	    *message = _notmuch_message_create (notmuch, notmuch, doc_id,
>> +						NULL);
>> +	    if (*message == NULL)
>> +		return NOTMUCH_STATUS_OUT_OF_MEMORY;
>> +	}
>>
>> -	return _notmuch_message_create (notmuch, notmuch, doc_id, NULL);
>> +	return NOTMUCH_STATUS_SUCCESS;
>>      } catch (const Xapian::Error &error) {
>>  	fprintf (stderr, "A Xapian exception occurred finding message: %s.\n",
>>  		 error.get_msg().c_str());
>>  	notmuch->exception_reported = TRUE;
>> -	return NULL;
>> +	*message = NULL;
>> +	return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
>>      }
>>  }
>>
>> @@ -1311,7 +1322,8 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
>>
>>  /* Find the thread ID to which the message with 'message_id' belongs.
>>   *
>> - * Always returns a newly talloced string belonging to 'ctx'.
>> + * Note: 'thread_id' must not be NULL!
>> + * On success '*thread_id' is set to a newly talloced string belonging to 'ctx'.
>>   *
>>   * Note: If there is no message in the database with the given
>>   * 'message_id' then a new thread_id will be allocated for this
>> @@ -1319,25 +1331,29 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
>>   * thread ID can be looked up if the message is added to the database
>>   * later).
>>   */
>> -static const char *
>> +static notmuch_status_t
>>  _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
>>  				  void *ctx,
>> -				  const char *message_id)
>> +				  const char *message_id,
>> +				  const char **thread_id)
>
>thread_id_ret?

Same as above, fixed.

>
>>  {
>> +    notmuch_status_t status;
>>      notmuch_message_t *message;
>>      string thread_id_string;
>> -    const char *thread_id;
>>      char *metadata_key;
>>      Xapian::WritableDatabase *db;
>>
>> -    message = notmuch_database_find_message (notmuch, message_id);
>> +    status = notmuch_database_find_message (notmuch, message_id, &message);
>> +
>> +    if (status)
>> +	return status;
>>
>>      if (message) {
>> -	thread_id = talloc_steal (ctx, notmuch_message_get_thread_id (message));
>> +	*thread_id = talloc_steal (ctx, notmuch_message_get_thread_id (message));
>>
>>  	notmuch_message_destroy (message);
>>
>> -	return thread_id;
>> +	return NOTMUCH_STATUS_SUCCESS;
>>      }
>>
>>      /* Message has not been seen yet.
>> @@ -1351,15 +1367,15 @@ _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
>>      thread_id_string = notmuch->xapian_db->get_metadata (metadata_key);
>>
>>      if (thread_id_string.empty()) {
>> -	thread_id = _notmuch_database_generate_thread_id (notmuch);
>> -	db->set_metadata (metadata_key, thread_id);
>> +	*thread_id = talloc_strdup (ctx, _notmuch_database_generate_thread_id (notmuch));
>> +	db->set_metadata (metadata_key, *thread_id);
>>      } else {
>> -	thread_id = thread_id_string.c_str();
>> +	*thread_id = talloc_strdup(ctx, thread_id_string.c_str());
>
>Missing space after talloc_strdup.

Oops, fixed.

>>      }
>>
>>      talloc_free (metadata_key);
>>
>> -    return talloc_strdup (ctx, thread_id);
>> +    return NOTMUCH_STATUS_SUCCESS;
>>  }
>>
>>  static notmuch_status_t
>> @@ -1446,9 +1462,12 @@ _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch,
>>  	_notmuch_message_add_term (message, "reference",
>>  				   parent_message_id);
>>
>> -	parent_thread_id = _resolve_message_id_to_thread_id (notmuch,
>> -							     message,
>> -							     parent_message_id);
>> +	ret = _resolve_message_id_to_thread_id (notmuch,
>> +						message,
>> +						parent_message_id,
>> +						&parent_thread_id);
>> +	if (ret)
>> +	    goto DONE;
>>
>>  	if (*thread_id == NULL) {
>>  	    *thread_id = talloc_strdup (message, parent_thread_id);
>> @@ -1759,11 +1778,12 @@ notmuch_status_t
>>  notmuch_database_remove_message (notmuch_database_t *notmuch,
>>  				 const char *filename)
>>  {
>> -    notmuch_message_t *message =
>> -	notmuch_database_find_message_by_filename (notmuch, filename);
>> -    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
>> +    notmuch_status_t status;
>> +    notmuch_message_t *message;
>>
>> -    if (message) {
>> +    status = notmuch_database_find_message_by_filename (notmuch, filename, &message);
>> +
>> +    if (status == NOTMUCH_STATUS_SUCCESS && message) {
>>  	    status = _notmuch_message_remove_filename (message, filename);
>>  	    if (status == NOTMUCH_STATUS_SUCCESS)
>>  		_notmuch_message_delete (message);
>
>This isn't a problem with your patch, but shouldn't this function be
>notmuch_message_destroy'ing message?
>

Exactly! I will provide a separate patch for this.

>> @@ -1774,24 +1794,27 @@ notmuch_database_remove_message (notmuch_database_t *notmuch,
>>      return status;
>>  }
>>
>> -notmuch_message_t *
>> +notmuch_status_t
>>  notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
>> -					   const char *filename)
>> +					   const char *filename,
>> +					   notmuch_message_t **message)
>
>message_ret?

Same as above, fixed.

>>  {
>>      void *local;
>>      const char *prefix = _find_prefix ("file-direntry");
>>      char *direntry, *term;
>>      Xapian::PostingIterator i, end;
>> -    notmuch_message_t *message = NULL;
>>      notmuch_status_t status;
>>
>> +    if (message == NULL)
>> +	return NOTMUCH_STATUS_NULL_POINTER;
>> +
>>      local = talloc_new (notmuch);
>>
>>      try {
>>  	status = _notmuch_database_filename_to_direntry (local, notmuch,
>>  							 filename, &direntry);
>>  	if (status)
>> -	    return NULL;
>> +	    goto DONE;
>>
>>  	term = talloc_asprintf (local, "%s%s", prefix, direntry);
>>
>> @@ -1800,19 +1823,24 @@ notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
>>  	if (i != end) {
>>  	    notmuch_private_status_t private_status;
>>
>> -	    message = _notmuch_message_create (notmuch, notmuch,
>> -					       *i, &private_status);
>> +	    *message = _notmuch_message_create (notmuch, notmuch,
>> +						*i, &private_status);
>> +	    if (*message == NULL)
>> +		status = NOTMUCH_STATUS_OUT_OF_MEMORY;
>>  	}
>>      } catch (const Xapian::Error &error) {
>>  	fprintf (stderr, "Error: A Xapian exception occurred finding message by filename: %s\n",
>>  		 error.get_msg().c_str());
>>  	notmuch->exception_reported = TRUE;
>> -	message = NULL;
>> +	status = NOTMUCH_STATUS_OUT_OF_MEMORY;
>>      }
>>
>> +  DONE:
>>      talloc_free (local);
>>
>> -    return message;
>> +    if (status)
>> +	*message = NULL;
>> +    return status;
>>  }
>>
>>  notmuch_string_list_t *
>> diff --git a/lib/message.cc b/lib/message.cc
>> index 531d304..2a85744 100644
>> --- a/lib/message.cc
>> +++ b/lib/message.cc
>> @@ -216,11 +216,11 @@ _notmuch_message_create_for_message_id (notmuch_database_t *notmuch,
>>      unsigned int doc_id;
>>      char *term;
>>
>> -    *status_ret = NOTMUCH_PRIVATE_STATUS_SUCCESS;
>> -
>> -    message = notmuch_database_find_message (notmuch, message_id);
>> +    *status_ret = (notmuch_private_status_t) notmuch_database_find_message (notmuch, message_id, &message);
>
>Long line, should probably be wrapped.

Done:
(notmuch_private_status_t) notmuch_database_find_message
looks like a single entity to my brain which makes wrapping rather
pointless though...

>>      if (message)
>>  	return talloc_steal (notmuch, message);
>> +    else if (*status_ret)
>> +	return NULL;
>>
>>      term = talloc_asprintf (NULL, "%s%s",
>>  			    _find_prefix ("id"), message_id);
>> diff --git a/lib/notmuch.h b/lib/notmuch.h
>> index 6d7a99f..08b4ce2 100644
>> --- a/lib/notmuch.h
>> +++ b/lib/notmuch.h
>> @@ -347,35 +347,60 @@ notmuch_database_remove_message (notmuch_database_t *database,
>>
>>  /* Find a message with the given message_id.
>>   *
>> - * If the database contains a message with the given message_id, then
>> - * a new notmuch_message_t object is returned. The caller should call
>> - * notmuch_message_destroy when done with the message.
>> + * If message with the given message_id is found then, on successful return
>
>"If a message"
>
>> + * (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to a message object.
>> + * The user should call notmuch_message_destroy when done with the message.
>
>Probably s/user/caller/, since "the user" is the person sitting at the
>keyboard.  (notmuch.h isn't very good about this, but it does use
>"caller" more often than "user").

As you wish sir, I can't say I care much about the wording.

>> - * This function returns NULL in the following situations:
>> + * On any failure or when the message is not found, this function initializes
>> + * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
>> + * user is supposed to check '*message' for NULL to find out whether the
>> + * message with the given message_id was found.
>>   *
>> - *	* No message is found with the given message_id
>> - *	* An out-of-memory situation occurs
>> - *	* A Xapian exception occurs
>> + * Note: The argument 'message' must not be NULL!
>
>Since it's clearly specified what happens if 'message' is NULL, this
>note isn't necessary.

Fair enough, removed.

>> + *
>> + * Return value:
>> + *
>> + * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'.
>> + *
>> + * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
>> + *
>> + * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating message object
>> + *
>> + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
>>   */
>> -notmuch_message_t *
>> +notmuch_status_t
>>  notmuch_database_find_message (notmuch_database_t *database,
>> -			       const char *message_id);
>> +			       const char *message_id,
>> +			       notmuch_message_t **message);
>>
>>  /* Find a message with the given filename.
>>   *
>> - * If the database contains a message with the given filename, then a
>> - * new notmuch_message_t object is returned.  The caller should call
>> - * notmuch_message_destroy when done with the message.
>> + * If the database contains a message with the given filename then, on
>> + * successful return (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to
>> + * a message object. The user should call notmuch_message_destroy when done
>> + * with the message.
>
>Same comment about "user" as above.

Same as above, fixed.

>>   *
>> - * This function returns NULL in the following situations:
>> + * On any failure or when the message is not found, this function initializes
>> + * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
>> + * user is supposed to check '*message' for NULL to find out whether the
>> + * message with the given filename is found.
>>   *
>> - *	* No message is found with the given filename
>> - *	* An out-of-memory situation occurs
>> - *	* A Xapian exception occurs
>> + * Note: The argument 'message' must not be NULL!
>
>Same comment about this note as above.

Same as above, removed.

>> + *
>> + * Return value:
>> + *
>> + * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'
>> + *
>> + * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
>> + *
>> + * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating the message object
>> + *
>> + * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
>>   */
>> -notmuch_message_t *
>> +notmuch_status_t
>>  notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
>> -					   const char *filename);
>> +					   const char *filename,
>> +					   notmuch_message_t **message);
>>
>>  /* Return a list of all tags found in the database.
>>   *
>> diff --git a/notmuch-new.c b/notmuch-new.c
>> index e79593c..96a1e31 100644
>> --- a/notmuch-new.c
>> +++ b/notmuch-new.c
>> @@ -743,7 +743,9 @@ remove_filename (notmuch_database_t *notmuch,
>>      status = notmuch_database_begin_atomic (notmuch);
>>      if (status)
>>  	return status;
>> -    message = notmuch_database_find_message_by_filename (notmuch, path);
>> +    status = notmuch_database_find_message_by_filename (notmuch, path, &message);
>> +    if (status || message == NULL)
>> +	return status;
>>      status = notmuch_database_remove_message (notmuch, path);
>>      if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
>>  	add_files_state->renamed_messages++;
>> diff --git a/notmuch-restore.c b/notmuch-restore.c
>> index f095f64..e4a5355 100644
>> --- a/notmuch-restore.c
>> +++ b/notmuch-restore.c
>> @@ -87,10 +87,13 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])
>>  	file_tags = xstrndup (line + match[2].rm_so,
>>  			      match[2].rm_eo - match[2].rm_so);
>>
>> -	message = notmuch_database_find_message (notmuch, message_id);
>> -	if (message == NULL) {
>> -	    fprintf (stderr, "Warning: Cannot apply tags to missing message: %s\n",
>> -		     message_id);
>> +	status = notmuch_database_find_message (notmuch, message_id, &message);
>> +	if (status || message == NULL) {
>> +	    fprintf (stderr, "Warning: Cannot apply tags to %smessage: %s\n",
>> +		     message ? "" : "missing ", message_id);
>> +	    if (status)
>> +		fprintf (stderr, "%s\n",
>> +			 notmuch_status_to_string(status));
>>  	    goto NEXT_LINE;
>>  	}
>>
>
>-- 
>Austin Clements                                      MIT/'06/PhD/CSAIL
>amdragon@mit.edu                           http://web.mit.edu/amdragon
>       Somewhere in the dream we call reality you will find me,
>              searching for the reality we call dreams.


          -alip

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 0/2] Better error handling
  2011-10-03 20:38                   ` [PATCH v1 1/1] lib: make find_message{, by_filename) " Ali Polatel
@ 2011-10-03 20:40                     ` Ali Polatel
  2011-10-03 20:40                       ` [PATCH v2 1/2] lib: destroy message object after message removal Ali Polatel
                                         ` (3 more replies)
  0 siblings, 4 replies; 30+ messages in thread
From: Ali Polatel @ 2011-10-03 20:40 UTC (permalink / raw)
  To: Austin Clements; +Cc: Ali Polatel, Notmuch Mailing List

From: Ali Polatel <alip@exherbo.org>

New set of patches addressing the issues in the mail
"id:20111003174308.GD17905@mit.edu"

Ali Polatel (2):
  lib: destroy message object after message removal
  lib: make find_message{,by_filename) report errors

 lib/database.cc   |   95 +++++++++++++++++++++++++++++++++++-----------------
 lib/message.cc    |    8 +++--
 lib/notmuch.h     |   60 +++++++++++++++++++++++----------
 notmuch-new.c     |    4 ++-
 notmuch-restore.c |   11 ++++--
 5 files changed, 120 insertions(+), 58 deletions(-)

-- 
1.7.6.1

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v2 1/2] lib: destroy message object after message removal
  2011-10-03 20:40                     ` [PATCH v2 0/2] Better error handling Ali Polatel
@ 2011-10-03 20:40                       ` Ali Polatel
  2011-10-03 20:40                       ` [PATCH v2 2/2] lib: make find_message{,by_filename) report errors Ali Polatel
                                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 30+ messages in thread
From: Ali Polatel @ 2011-10-03 20:40 UTC (permalink / raw)
  To: Austin Clements; +Cc: Ali Polatel, Notmuch Mailing List

From: Ali Polatel <alip@exherbo.org>

notmuch_database_remove_message() must call notmuch_message_destroy()
once it is done handling message removal.
---
 lib/database.cc |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 9299c8d..d43e114 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -1769,6 +1769,8 @@ notmuch_database_remove_message (notmuch_database_t *notmuch,
 		_notmuch_message_delete (message);
 	    else if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)
 		_notmuch_message_sync (message);
+
+	    notmuch_message_destroy (message);
     }
 
     return status;
-- 
1.7.6.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2 2/2] lib: make find_message{,by_filename) report errors
  2011-10-03 20:40                     ` [PATCH v2 0/2] Better error handling Ali Polatel
  2011-10-03 20:40                       ` [PATCH v2 1/2] lib: destroy message object after message removal Ali Polatel
@ 2011-10-03 20:40                       ` Ali Polatel
  2011-10-03 20:53                       ` [PATCH v2 0/2] Better error handling Ali Polatel
  2011-10-03 21:03                       ` Austin Clements
  3 siblings, 0 replies; 30+ messages in thread
From: Ali Polatel @ 2011-10-03 20:40 UTC (permalink / raw)
  To: Austin Clements; +Cc: Ali Polatel, Notmuch Mailing List

From: Ali Polatel <alip@exherbo.org>

Previously, the functions notmuch_database_find_message() and
notmuch_database_find_message_by_filename() functions did not properly
report error condition to the library user.

For more information, read the thread on the notmuch mailing list
starting with my mail "id:871uv2unfd.fsf@gmail.com"

Make these functions accept a pointer to 'notmuch_message_t' as argument
and return notmuch_status_t which may be used to check for any error
condition.

restore: Modify for the new notmuch_database_find_message()
new: Modify for the new notmuch_database_find_message_by_filename()
---
 lib/database.cc   |   93 +++++++++++++++++++++++++++++++++++-----------------
 lib/message.cc    |    8 +++--
 lib/notmuch.h     |   60 +++++++++++++++++++++++-----------
 notmuch-new.c     |    4 ++-
 notmuch-restore.c |   11 ++++--
 5 files changed, 118 insertions(+), 58 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index d43e114..cf0cc8a 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -360,13 +360,17 @@ _message_id_compressed (void *ctx, const char *message_id)
     return compressed;
 }
 
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message (notmuch_database_t *notmuch,
-			       const char *message_id)
+			       const char *message_id,
+			       notmuch_message_t **message_ret)
 {
     notmuch_private_status_t status;
     unsigned int doc_id;
 
+    if (message_ret == NULL)
+	return NOTMUCH_STATUS_NULL_POINTER;
+
     if (strlen (message_id) > NOTMUCH_MESSAGE_ID_MAX)
 	message_id = _message_id_compressed (notmuch, message_id);
 
@@ -375,14 +379,21 @@ notmuch_database_find_message (notmuch_database_t *notmuch,
 						       message_id, &doc_id);
 
 	if (status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND)
-	    return NULL;
+	    *message_ret = NULL;
+	else {
+	    *message_ret = _notmuch_message_create (notmuch, notmuch, doc_id,
+						    NULL);
+	    if (*message_ret == NULL)
+		return NOTMUCH_STATUS_OUT_OF_MEMORY;
+	}
 
-	return _notmuch_message_create (notmuch, notmuch, doc_id, NULL);
+	return NOTMUCH_STATUS_SUCCESS;
     } catch (const Xapian::Error &error) {
 	fprintf (stderr, "A Xapian exception occurred finding message: %s.\n",
 		 error.get_msg().c_str());
 	notmuch->exception_reported = TRUE;
-	return NULL;
+	*message_ret = NULL;
+	return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
     }
 }
 
@@ -1311,7 +1322,8 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
 
 /* Find the thread ID to which the message with 'message_id' belongs.
  *
- * Always returns a newly talloced string belonging to 'ctx'.
+ * Note: 'thread_id' must not be NULL!
+ * On success '*thread_id' is set to a newly talloced string belonging to 'ctx'.
  *
  * Note: If there is no message in the database with the given
  * 'message_id' then a new thread_id will be allocated for this
@@ -1319,25 +1331,30 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
  * thread ID can be looked up if the message is added to the database
  * later).
  */
-static const char *
+static notmuch_status_t
 _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
 				  void *ctx,
-				  const char *message_id)
+				  const char *message_id,
+				  const char **thread_id_ret)
 {
+    notmuch_status_t status;
     notmuch_message_t *message;
     string thread_id_string;
-    const char *thread_id;
     char *metadata_key;
     Xapian::WritableDatabase *db;
 
-    message = notmuch_database_find_message (notmuch, message_id);
+    status = notmuch_database_find_message (notmuch, message_id, &message);
+
+    if (status)
+	return status;
 
     if (message) {
-	thread_id = talloc_steal (ctx, notmuch_message_get_thread_id (message));
+	*thread_id_ret = talloc_steal (ctx,
+				       notmuch_message_get_thread_id (message));
 
 	notmuch_message_destroy (message);
 
-	return thread_id;
+	return NOTMUCH_STATUS_SUCCESS;
     }
 
     /* Message has not been seen yet.
@@ -1351,15 +1368,16 @@ _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
     thread_id_string = notmuch->xapian_db->get_metadata (metadata_key);
 
     if (thread_id_string.empty()) {
-	thread_id = _notmuch_database_generate_thread_id (notmuch);
-	db->set_metadata (metadata_key, thread_id);
+	*thread_id_ret = talloc_strdup (ctx,
+					_notmuch_database_generate_thread_id (notmuch));
+	db->set_metadata (metadata_key, *thread_id_ret);
     } else {
-	thread_id = thread_id_string.c_str();
+	*thread_id_ret = talloc_strdup (ctx, thread_id_string.c_str());
     }
 
     talloc_free (metadata_key);
 
-    return talloc_strdup (ctx, thread_id);
+    return NOTMUCH_STATUS_SUCCESS;
 }
 
 static notmuch_status_t
@@ -1446,9 +1464,12 @@ _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch,
 	_notmuch_message_add_term (message, "reference",
 				   parent_message_id);
 
-	parent_thread_id = _resolve_message_id_to_thread_id (notmuch,
-							     message,
-							     parent_message_id);
+	ret = _resolve_message_id_to_thread_id (notmuch,
+						message,
+						parent_message_id,
+						&parent_thread_id);
+	if (ret)
+	    goto DONE;
 
 	if (*thread_id == NULL) {
 	    *thread_id = talloc_strdup (message, parent_thread_id);
@@ -1759,11 +1780,13 @@ notmuch_status_t
 notmuch_database_remove_message (notmuch_database_t *notmuch,
 				 const char *filename)
 {
-    notmuch_message_t *message =
-	notmuch_database_find_message_by_filename (notmuch, filename);
-    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+    notmuch_status_t status;
+    notmuch_message_t *message;
 
-    if (message) {
+    status = notmuch_database_find_message_by_filename (notmuch, filename,
+							&message);
+
+    if (status == NOTMUCH_STATUS_SUCCESS && message) {
 	    status = _notmuch_message_remove_filename (message, filename);
 	    if (status == NOTMUCH_STATUS_SUCCESS)
 		_notmuch_message_delete (message);
@@ -1776,24 +1799,27 @@ notmuch_database_remove_message (notmuch_database_t *notmuch,
     return status;
 }
 
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
-					   const char *filename)
+					   const char *filename,
+					   notmuch_message_t **message_ret)
 {
     void *local;
     const char *prefix = _find_prefix ("file-direntry");
     char *direntry, *term;
     Xapian::PostingIterator i, end;
-    notmuch_message_t *message = NULL;
     notmuch_status_t status;
 
+    if (message_ret == NULL)
+	return NOTMUCH_STATUS_NULL_POINTER;
+
     local = talloc_new (notmuch);
 
     try {
 	status = _notmuch_database_filename_to_direntry (local, notmuch,
 							 filename, &direntry);
 	if (status)
-	    return NULL;
+	    goto DONE;
 
 	term = talloc_asprintf (local, "%s%s", prefix, direntry);
 
@@ -1802,19 +1828,24 @@ notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
 	if (i != end) {
 	    notmuch_private_status_t private_status;
 
-	    message = _notmuch_message_create (notmuch, notmuch,
-					       *i, &private_status);
+	    *message_ret = _notmuch_message_create (notmuch, notmuch, *i,
+						    &private_status);
+	    if (*message_ret == NULL)
+		status = NOTMUCH_STATUS_OUT_OF_MEMORY;
 	}
     } catch (const Xapian::Error &error) {
 	fprintf (stderr, "Error: A Xapian exception occurred finding message by filename: %s\n",
 		 error.get_msg().c_str());
 	notmuch->exception_reported = TRUE;
-	message = NULL;
+	status = NOTMUCH_STATUS_OUT_OF_MEMORY;
     }
 
+  DONE:
     talloc_free (local);
 
-    return message;
+    if (status)
+	*message_ret = NULL;
+    return status;
 }
 
 notmuch_string_list_t *
diff --git a/lib/message.cc b/lib/message.cc
index 531d304..8f22e02 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -216,11 +216,13 @@ _notmuch_message_create_for_message_id (notmuch_database_t *notmuch,
     unsigned int doc_id;
     char *term;
 
-    *status_ret = NOTMUCH_PRIVATE_STATUS_SUCCESS;
-
-    message = notmuch_database_find_message (notmuch, message_id);
+    *status_ret = (notmuch_private_status_t) notmuch_database_find_message (notmuch,
+									    message_id,
+									    &message);
     if (message)
 	return talloc_steal (notmuch, message);
+    else if (*status_ret)
+	return NULL;
 
     term = talloc_asprintf (NULL, "%s%s",
 			    _find_prefix ("id"), message_id);
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 6d7a99f..9d7f8f5 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -286,7 +286,7 @@ notmuch_database_get_directory (notmuch_database_t *database,
  * If 'message' is not NULL, then, on successful return
  * (NOTMUCH_STATUS_SUCCESS or NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) '*message'
  * will be initialized to a message object that can be used for things
- * such as adding tags to the just-added message. The user should call
+ * such as adding tags to the just-added message. The caller should call
  * notmuch_message_destroy when done with the message. On any failure
  * '*message' will be set to NULL.
  *
@@ -347,35 +347,57 @@ notmuch_database_remove_message (notmuch_database_t *database,
 
 /* Find a message with the given message_id.
  *
- * If the database contains a message with the given message_id, then
- * a new notmuch_message_t object is returned. The caller should call
- * notmuch_message_destroy when done with the message.
+ * If a message with the given message_id is found then, on successful return
+ * (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to a message
+ * object.  The caller should call notmuch_message_destroy when done with the
+ * message.
  *
- * This function returns NULL in the following situations:
+ * On any failure or when the message is not found, this function initializes
+ * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
+ * caller is supposed to check '*message' for NULL to find out whether the
+ * message with the given message_id was found.
  *
- *	* No message is found with the given message_id
- *	* An out-of-memory situation occurs
- *	* A Xapian exception occurs
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'.
+ *
+ * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
+ *
+ * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating message object
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
  */
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message (notmuch_database_t *database,
-			       const char *message_id);
+			       const char *message_id,
+			       notmuch_message_t **message);
 
 /* Find a message with the given filename.
  *
- * If the database contains a message with the given filename, then a
- * new notmuch_message_t object is returned.  The caller should call 
- * notmuch_message_destroy when done with the message.
+ * If the database contains a message with the given filename then, on
+ * successful return (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to
+ * a message object. The caller should call notmuch_message_destroy when done
+ * with the message.
  *
- * This function returns NULL in the following situations:
+ * On any failure or when the message is not found, this function initializes
+ * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
+ * caller is supposed to check '*message' for NULL to find out whether the
+ * message with the given filename is found.
  *
- *	* No message is found with the given filename
- *	* An out-of-memory situation occurs
- *	* A Xapian exception occurs
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'
+ *
+ * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
+ *
+ * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating the message object
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
  */
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
-					   const char *filename);
+					   const char *filename,
+					   notmuch_message_t **message);
 
 /* Return a list of all tags found in the database.
  *
diff --git a/notmuch-new.c b/notmuch-new.c
index e79593c..96a1e31 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -743,7 +743,9 @@ remove_filename (notmuch_database_t *notmuch,
     status = notmuch_database_begin_atomic (notmuch);
     if (status)
 	return status;
-    message = notmuch_database_find_message_by_filename (notmuch, path);
+    status = notmuch_database_find_message_by_filename (notmuch, path, &message);
+    if (status || message == NULL)
+	return status;
     status = notmuch_database_remove_message (notmuch, path);
     if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
 	add_files_state->renamed_messages++;
diff --git a/notmuch-restore.c b/notmuch-restore.c
index f095f64..e4a5355 100644
--- a/notmuch-restore.c
+++ b/notmuch-restore.c
@@ -87,10 +87,13 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])
 	file_tags = xstrndup (line + match[2].rm_so,
 			      match[2].rm_eo - match[2].rm_so);
 
-	message = notmuch_database_find_message (notmuch, message_id);
-	if (message == NULL) {
-	    fprintf (stderr, "Warning: Cannot apply tags to missing message: %s\n",
-		     message_id);
+	status = notmuch_database_find_message (notmuch, message_id, &message);
+	if (status || message == NULL) {
+	    fprintf (stderr, "Warning: Cannot apply tags to %smessage: %s\n",
+		     message ? "" : "missing ", message_id);
+	    if (status)
+		fprintf (stderr, "%s\n",
+			 notmuch_status_to_string(status));
 	    goto NEXT_LINE;
 	}
 
-- 
1.7.6.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 0/2] Better error handling
  2011-10-03 20:40                     ` [PATCH v2 0/2] Better error handling Ali Polatel
  2011-10-03 20:40                       ` [PATCH v2 1/2] lib: destroy message object after message removal Ali Polatel
  2011-10-03 20:40                       ` [PATCH v2 2/2] lib: make find_message{,by_filename) report errors Ali Polatel
@ 2011-10-03 20:53                       ` Ali Polatel
  2011-10-03 21:03                       ` Austin Clements
  3 siblings, 0 replies; 30+ messages in thread
From: Ali Polatel @ 2011-10-03 20:53 UTC (permalink / raw)
  To: Austin Clements; +Cc: Notmuch Mailing List

[-- Attachment #1: Type: text/plain, Size: 750 bytes --]

Ali Polatel yazmış:
>From: Ali Polatel <alip@exherbo.org>
>
>New set of patches addressing the issues in the mail
>"id:20111003174308.GD17905@mit.edu"

You may also find the commits in my notmuch repository:
git://github.com/alip/notmuch.git branch: find_message-v2

>Ali Polatel (2):
>  lib: destroy message object after message removal
>  lib: make find_message{,by_filename) report errors
>
> lib/database.cc   |   95 +++++++++++++++++++++++++++++++++++-----------------
> lib/message.cc    |    8 +++--
> lib/notmuch.h     |   60 +++++++++++++++++++++++----------
> notmuch-new.c     |    4 ++-
> notmuch-restore.c |   11 ++++--
> 5 files changed, 120 insertions(+), 58 deletions(-)
>
>-- 
>1.7.6.1
>


         -alip

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2 0/2] Better error handling
  2011-10-03 20:40                     ` [PATCH v2 0/2] Better error handling Ali Polatel
                                         ` (2 preceding siblings ...)
  2011-10-03 20:53                       ` [PATCH v2 0/2] Better error handling Ali Polatel
@ 2011-10-03 21:03                       ` Austin Clements
  3 siblings, 0 replies; 30+ messages in thread
From: Austin Clements @ 2011-10-03 21:03 UTC (permalink / raw)
  To: Ali Polatel; +Cc: Ali Polatel, Notmuch Mailing List

LGTM.

Quoth Ali Polatel on Oct 03 at 11:40 pm:
> From: Ali Polatel <alip@exherbo.org>
> 
> New set of patches addressing the issues in the mail
> "id:20111003174308.GD17905@mit.edu"
> 
> Ali Polatel (2):
>   lib: destroy message object after message removal
>   lib: make find_message{,by_filename) report errors
> 
>  lib/database.cc   |   95 +++++++++++++++++++++++++++++++++++-----------------
>  lib/message.cc    |    8 +++--
>  lib/notmuch.h     |   60 +++++++++++++++++++++++----------
>  notmuch-new.c     |    4 ++-
>  notmuch-restore.c |   11 ++++--
>  5 files changed, 120 insertions(+), 58 deletions(-)

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH] lib: make find_message{,by_filename) report errors
  2011-10-01  8:12           ` [PATCH] lib: make find_message{,by_filename) report errors Ali Polatel
  2011-10-01  8:12             ` Ali Polatel
  2011-10-03 16:49             ` [PATCH v1 0/1] " Ali Polatel
@ 2011-10-04  1:10             ` David Bremner
  2011-10-04  5:00               ` Ali Polatel
  2 siblings, 1 reply; 30+ messages in thread
From: David Bremner @ 2011-10-04  1:10 UTC (permalink / raw)
  To: Ali Polatel, Austin Clements; +Cc: Notmuch Mailing List

On Sat,  1 Oct 2011 11:12:23 +0300, Ali Polatel <polatel@gmail.com> wrote:
> From: Ali Polatel <alip@exherbo.org>
> 
> Looks like the patch did not make it correctly the first time.
> Resending using git-send-email™
> 
> You may also find the commit in my notmuch repository:
> git://github.com/alip/notmuch.git branch: find_message


Hi Ali;

Thanks for reworking this patch. I looked at branch find_message-v2
in your repo. I have a few comments.

- In the comments for _resolve_message_id_to_thread_id I guess thread_id
  should be thread_id_ret?

- in notmuch_database_find_message_by_file_name, I'm not sure why you
  set status to NOTMUCH_STATUS_OUT_OF_MEMORY in the catch block. Is this
  a typo?

- after the DONE: label of the same routine, how is *message_ret destroyed?
  does it need to wait until the talloc context "notmuch" is freed?

- I don't really get the change of user to caller around notmuch.h:286
  It is not a big deal, but I guess we should try to be consistent.

David

 

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH] lib: make find_message{,by_filename) report errors
  2011-10-04  1:10             ` [PATCH] lib: make find_message{,by_filename) report errors David Bremner
@ 2011-10-04  5:00               ` Ali Polatel
  2011-10-04  5:06                 ` [PATCH v3 0/2] Better error handling Ali Polatel
  0 siblings, 1 reply; 30+ messages in thread
From: Ali Polatel @ 2011-10-04  5:00 UTC (permalink / raw)
  To: David Bremner; +Cc: Notmuch Mailing List, Austin Clements

[-- Attachment #1: Type: text/plain, Size: 1538 bytes --]

David Bremner yazmış:
>On Sat,  1 Oct 2011 11:12:23 +0300, Ali Polatel <polatel@gmail.com> wrote:
>> From: Ali Polatel <alip@exherbo.org>
>>
>> Looks like the patch did not make it correctly the first time.
>> Resending using git-send-email™
>>
>> You may also find the commit in my notmuch repository:
>> git://github.com/alip/notmuch.git branch: find_message
>
>
>Hi Ali;
>
>Thanks for reworking this patch. I looked at branch find_message-v2
>in your repo. I have a few comments.

Thanks for going over the patch, expect a new set of patches soon!

>- In the comments for _resolve_message_id_to_thread_id I guess thread_id
>  should be thread_id_ret?

Fixed.

>- in notmuch_database_find_message_by_file_name, I'm not sure why you
>  set status to NOTMUCH_STATUS_OUT_OF_MEMORY in the catch block. Is this
>  a typo?

Looks like a copy & paste error. I must have blindly copied the error
from the previous block. Fixed.

>- after the DONE: label of the same routine, how is *message_ret destroyed?
>  does it need to wait until the talloc context "notmuch" is freed?

Yes, I have modified it to call notmuch_message_destroy() in case
'*message_ret' is non-NULL after the DONE:

>- I don't really get the change of user to caller around notmuch.h:286
>  It is not a big deal, but I guess we should try to be consistent.

I don't get what you mean by consistency here but this hunk is unrelated
to the problem which the patch is trying to address.
Reverted.

>David
>
>

         -alip

[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v3 0/2] Better error handling
  2011-10-04  5:00               ` Ali Polatel
@ 2011-10-04  5:06                 ` Ali Polatel
  2011-10-04  5:06                   ` [PATCH v3 1/2] lib: destroy message object after message removal Ali Polatel
                                     ` (2 more replies)
  0 siblings, 3 replies; 30+ messages in thread
From: Ali Polatel @ 2011-10-04  5:06 UTC (permalink / raw)
  To: David Bremner; +Cc: Ali Polatel, Notmuch Mailing List, Austin Clements

From: Ali Polatel <alip@exherbo.org>

New set of patches addressing the issues in the mail
"id:8739f9muhp.fsf@zancas.localnet"

You may also find the commits in my notmuch repository:
git://github.com/alip/notmuch.git branch: find_message-v3

Ali Polatel (2):
  lib: destroy message object after message removal
  lib: make find_message{,by_filename) report errors

 lib/database.cc   |   98 ++++++++++++++++++++++++++++++++++++-----------------
 lib/message.cc    |    8 +++--
 lib/notmuch.h     |   58 +++++++++++++++++++++----------
 notmuch-new.c     |    4 ++-
 notmuch-restore.c |   11 ++++--
 5 files changed, 122 insertions(+), 57 deletions(-)

-- 
1.7.6.1

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v3 1/2] lib: destroy message object after message removal
  2011-10-04  5:06                 ` [PATCH v3 0/2] Better error handling Ali Polatel
@ 2011-10-04  5:06                   ` Ali Polatel
  2011-10-04  5:06                   ` [PATCH v3 2/2] lib: make find_message{,by_filename) report errors Ali Polatel
  2011-10-04 10:43                   ` [PATCH v3 0/2] Better error handling David Bremner
  2 siblings, 0 replies; 30+ messages in thread
From: Ali Polatel @ 2011-10-04  5:06 UTC (permalink / raw)
  To: David Bremner; +Cc: Ali Polatel, Notmuch Mailing List, Austin Clements

From: Ali Polatel <alip@exherbo.org>

notmuch_database_remove_message() must call notmuch_message_destroy()
once it is done handling message removal.
---
 lib/database.cc |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index 9299c8d..d43e114 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -1769,6 +1769,8 @@ notmuch_database_remove_message (notmuch_database_t *notmuch,
 		_notmuch_message_delete (message);
 	    else if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID)
 		_notmuch_message_sync (message);
+
+	    notmuch_message_destroy (message);
     }
 
     return status;
-- 
1.7.6.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v3 2/2] lib: make find_message{,by_filename) report errors
  2011-10-04  5:06                 ` [PATCH v3 0/2] Better error handling Ali Polatel
  2011-10-04  5:06                   ` [PATCH v3 1/2] lib: destroy message object after message removal Ali Polatel
@ 2011-10-04  5:06                   ` Ali Polatel
  2011-10-04 10:43                   ` [PATCH v3 0/2] Better error handling David Bremner
  2 siblings, 0 replies; 30+ messages in thread
From: Ali Polatel @ 2011-10-04  5:06 UTC (permalink / raw)
  To: David Bremner; +Cc: Ali Polatel, Notmuch Mailing List, Austin Clements

From: Ali Polatel <alip@exherbo.org>

Previously, the functions notmuch_database_find_message() and
notmuch_database_find_message_by_filename() functions did not properly
report error condition to the library user.

For more information, read the thread on the notmuch mailing list
starting with my mail "id:871uv2unfd.fsf@gmail.com"

Make these functions accept a pointer to 'notmuch_message_t' as argument
and return notmuch_status_t which may be used to check for any error
condition.

restore: Modify for the new notmuch_database_find_message()
new: Modify for the new notmuch_database_find_message_by_filename()
---
 lib/database.cc   |   96 ++++++++++++++++++++++++++++++++++++-----------------
 lib/message.cc    |    8 +++--
 lib/notmuch.h     |   58 ++++++++++++++++++++++----------
 notmuch-new.c     |    4 ++-
 notmuch-restore.c |   11 ++++--
 5 files changed, 120 insertions(+), 57 deletions(-)

diff --git a/lib/database.cc b/lib/database.cc
index d43e114..e77fd53 100644
--- a/lib/database.cc
+++ b/lib/database.cc
@@ -360,13 +360,17 @@ _message_id_compressed (void *ctx, const char *message_id)
     return compressed;
 }
 
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message (notmuch_database_t *notmuch,
-			       const char *message_id)
+			       const char *message_id,
+			       notmuch_message_t **message_ret)
 {
     notmuch_private_status_t status;
     unsigned int doc_id;
 
+    if (message_ret == NULL)
+	return NOTMUCH_STATUS_NULL_POINTER;
+
     if (strlen (message_id) > NOTMUCH_MESSAGE_ID_MAX)
 	message_id = _message_id_compressed (notmuch, message_id);
 
@@ -375,14 +379,21 @@ notmuch_database_find_message (notmuch_database_t *notmuch,
 						       message_id, &doc_id);
 
 	if (status == NOTMUCH_PRIVATE_STATUS_NO_DOCUMENT_FOUND)
-	    return NULL;
+	    *message_ret = NULL;
+	else {
+	    *message_ret = _notmuch_message_create (notmuch, notmuch, doc_id,
+						    NULL);
+	    if (*message_ret == NULL)
+		return NOTMUCH_STATUS_OUT_OF_MEMORY;
+	}
 
-	return _notmuch_message_create (notmuch, notmuch, doc_id, NULL);
+	return NOTMUCH_STATUS_SUCCESS;
     } catch (const Xapian::Error &error) {
 	fprintf (stderr, "A Xapian exception occurred finding message: %s.\n",
 		 error.get_msg().c_str());
 	notmuch->exception_reported = TRUE;
-	return NULL;
+	*message_ret = NULL;
+	return NOTMUCH_STATUS_XAPIAN_EXCEPTION;
     }
 }
 
@@ -1311,7 +1322,9 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
 
 /* Find the thread ID to which the message with 'message_id' belongs.
  *
- * Always returns a newly talloced string belonging to 'ctx'.
+ * Note: 'thread_id_ret' must not be NULL!
+ * On success '*thread_id_ret' is set to a newly talloced string belonging to
+ * 'ctx'.
  *
  * Note: If there is no message in the database with the given
  * 'message_id' then a new thread_id will be allocated for this
@@ -1319,25 +1332,30 @@ _get_metadata_thread_id_key (void *ctx, const char *message_id)
  * thread ID can be looked up if the message is added to the database
  * later).
  */
-static const char *
+static notmuch_status_t
 _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
 				  void *ctx,
-				  const char *message_id)
+				  const char *message_id,
+				  const char **thread_id_ret)
 {
+    notmuch_status_t status;
     notmuch_message_t *message;
     string thread_id_string;
-    const char *thread_id;
     char *metadata_key;
     Xapian::WritableDatabase *db;
 
-    message = notmuch_database_find_message (notmuch, message_id);
+    status = notmuch_database_find_message (notmuch, message_id, &message);
+
+    if (status)
+	return status;
 
     if (message) {
-	thread_id = talloc_steal (ctx, notmuch_message_get_thread_id (message));
+	*thread_id_ret = talloc_steal (ctx,
+				       notmuch_message_get_thread_id (message));
 
 	notmuch_message_destroy (message);
 
-	return thread_id;
+	return NOTMUCH_STATUS_SUCCESS;
     }
 
     /* Message has not been seen yet.
@@ -1351,15 +1369,16 @@ _resolve_message_id_to_thread_id (notmuch_database_t *notmuch,
     thread_id_string = notmuch->xapian_db->get_metadata (metadata_key);
 
     if (thread_id_string.empty()) {
-	thread_id = _notmuch_database_generate_thread_id (notmuch);
-	db->set_metadata (metadata_key, thread_id);
+	*thread_id_ret = talloc_strdup (ctx,
+					_notmuch_database_generate_thread_id (notmuch));
+	db->set_metadata (metadata_key, *thread_id_ret);
     } else {
-	thread_id = thread_id_string.c_str();
+	*thread_id_ret = talloc_strdup (ctx, thread_id_string.c_str());
     }
 
     talloc_free (metadata_key);
 
-    return talloc_strdup (ctx, thread_id);
+    return NOTMUCH_STATUS_SUCCESS;
 }
 
 static notmuch_status_t
@@ -1446,9 +1465,12 @@ _notmuch_database_link_message_to_parents (notmuch_database_t *notmuch,
 	_notmuch_message_add_term (message, "reference",
 				   parent_message_id);
 
-	parent_thread_id = _resolve_message_id_to_thread_id (notmuch,
-							     message,
-							     parent_message_id);
+	ret = _resolve_message_id_to_thread_id (notmuch,
+						message,
+						parent_message_id,
+						&parent_thread_id);
+	if (ret)
+	    goto DONE;
 
 	if (*thread_id == NULL) {
 	    *thread_id = talloc_strdup (message, parent_thread_id);
@@ -1759,11 +1781,13 @@ notmuch_status_t
 notmuch_database_remove_message (notmuch_database_t *notmuch,
 				 const char *filename)
 {
-    notmuch_message_t *message =
-	notmuch_database_find_message_by_filename (notmuch, filename);
-    notmuch_status_t status = NOTMUCH_STATUS_SUCCESS;
+    notmuch_status_t status;
+    notmuch_message_t *message;
 
-    if (message) {
+    status = notmuch_database_find_message_by_filename (notmuch, filename,
+							&message);
+
+    if (status == NOTMUCH_STATUS_SUCCESS && message) {
 	    status = _notmuch_message_remove_filename (message, filename);
 	    if (status == NOTMUCH_STATUS_SUCCESS)
 		_notmuch_message_delete (message);
@@ -1776,24 +1800,27 @@ notmuch_database_remove_message (notmuch_database_t *notmuch,
     return status;
 }
 
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
-					   const char *filename)
+					   const char *filename,
+					   notmuch_message_t **message_ret)
 {
     void *local;
     const char *prefix = _find_prefix ("file-direntry");
     char *direntry, *term;
     Xapian::PostingIterator i, end;
-    notmuch_message_t *message = NULL;
     notmuch_status_t status;
 
+    if (message_ret == NULL)
+	return NOTMUCH_STATUS_NULL_POINTER;
+
     local = talloc_new (notmuch);
 
     try {
 	status = _notmuch_database_filename_to_direntry (local, notmuch,
 							 filename, &direntry);
 	if (status)
-	    return NULL;
+	    goto DONE;
 
 	term = talloc_asprintf (local, "%s%s", prefix, direntry);
 
@@ -1802,19 +1829,26 @@ notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
 	if (i != end) {
 	    notmuch_private_status_t private_status;
 
-	    message = _notmuch_message_create (notmuch, notmuch,
-					       *i, &private_status);
+	    *message_ret = _notmuch_message_create (notmuch, notmuch, *i,
+						    &private_status);
+	    if (*message_ret == NULL)
+		status = NOTMUCH_STATUS_OUT_OF_MEMORY;
 	}
     } catch (const Xapian::Error &error) {
 	fprintf (stderr, "Error: A Xapian exception occurred finding message by filename: %s\n",
 		 error.get_msg().c_str());
 	notmuch->exception_reported = TRUE;
-	message = NULL;
+	status = NOTMUCH_STATUS_XAPIAN_EXCEPTION;
     }
 
+  DONE:
     talloc_free (local);
 
-    return message;
+    if (status && *message_ret) {
+	notmuch_message_destroy (*message_ret);
+	*message_ret = NULL;
+    }
+    return status;
 }
 
 notmuch_string_list_t *
diff --git a/lib/message.cc b/lib/message.cc
index 531d304..8f22e02 100644
--- a/lib/message.cc
+++ b/lib/message.cc
@@ -216,11 +216,13 @@ _notmuch_message_create_for_message_id (notmuch_database_t *notmuch,
     unsigned int doc_id;
     char *term;
 
-    *status_ret = NOTMUCH_PRIVATE_STATUS_SUCCESS;
-
-    message = notmuch_database_find_message (notmuch, message_id);
+    *status_ret = (notmuch_private_status_t) notmuch_database_find_message (notmuch,
+									    message_id,
+									    &message);
     if (message)
 	return talloc_steal (notmuch, message);
+    else if (*status_ret)
+	return NULL;
 
     term = talloc_asprintf (NULL, "%s%s",
 			    _find_prefix ("id"), message_id);
diff --git a/lib/notmuch.h b/lib/notmuch.h
index 6d7a99f..c4330e4 100644
--- a/lib/notmuch.h
+++ b/lib/notmuch.h
@@ -347,35 +347,57 @@ notmuch_database_remove_message (notmuch_database_t *database,
 
 /* Find a message with the given message_id.
  *
- * If the database contains a message with the given message_id, then
- * a new notmuch_message_t object is returned. The caller should call
- * notmuch_message_destroy when done with the message.
+ * If a message with the given message_id is found then, on successful return
+ * (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to a message
+ * object.  The caller should call notmuch_message_destroy when done with the
+ * message.
  *
- * This function returns NULL in the following situations:
+ * On any failure or when the message is not found, this function initializes
+ * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
+ * caller is supposed to check '*message' for NULL to find out whether the
+ * message with the given message_id was found.
  *
- *	* No message is found with the given message_id
- *	* An out-of-memory situation occurs
- *	* A Xapian exception occurs
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'.
+ *
+ * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
+ *
+ * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating message object
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
  */
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message (notmuch_database_t *database,
-			       const char *message_id);
+			       const char *message_id,
+			       notmuch_message_t **message);
 
 /* Find a message with the given filename.
  *
- * If the database contains a message with the given filename, then a
- * new notmuch_message_t object is returned.  The caller should call 
- * notmuch_message_destroy when done with the message.
+ * If the database contains a message with the given filename then, on
+ * successful return (NOTMUCH_STATUS_SUCCESS) '*message' will be initialized to
+ * a message object. The caller should call notmuch_message_destroy when done
+ * with the message.
  *
- * This function returns NULL in the following situations:
+ * On any failure or when the message is not found, this function initializes
+ * '*message' to NULL. This means, when NOTMUCH_STATUS_SUCCESS is returned, the
+ * caller is supposed to check '*message' for NULL to find out whether the
+ * message with the given filename is found.
  *
- *	* No message is found with the given filename
- *	* An out-of-memory situation occurs
- *	* A Xapian exception occurs
+ * Return value:
+ *
+ * NOTMUCH_STATUS_SUCCESS: Successful return, check '*message'
+ *
+ * NOTMUCH_STATUS_NULL_POINTER: The given 'message' argument is NULL
+ *
+ * NOTMUCH_STATUS_OUT_OF_MEMORY: Out of memory, creating the message object
+ *
+ * NOTMUCH_STATUS_XAPIAN_EXCEPTION: A Xapian exception occurred
  */
-notmuch_message_t *
+notmuch_status_t
 notmuch_database_find_message_by_filename (notmuch_database_t *notmuch,
-					   const char *filename);
+					   const char *filename,
+					   notmuch_message_t **message);
 
 /* Return a list of all tags found in the database.
  *
diff --git a/notmuch-new.c b/notmuch-new.c
index e79593c..96a1e31 100644
--- a/notmuch-new.c
+++ b/notmuch-new.c
@@ -743,7 +743,9 @@ remove_filename (notmuch_database_t *notmuch,
     status = notmuch_database_begin_atomic (notmuch);
     if (status)
 	return status;
-    message = notmuch_database_find_message_by_filename (notmuch, path);
+    status = notmuch_database_find_message_by_filename (notmuch, path, &message);
+    if (status || message == NULL)
+	return status;
     status = notmuch_database_remove_message (notmuch, path);
     if (status == NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
 	add_files_state->renamed_messages++;
diff --git a/notmuch-restore.c b/notmuch-restore.c
index f095f64..e4a5355 100644
--- a/notmuch-restore.c
+++ b/notmuch-restore.c
@@ -87,10 +87,13 @@ notmuch_restore_command (unused (void *ctx), int argc, char *argv[])
 	file_tags = xstrndup (line + match[2].rm_so,
 			      match[2].rm_eo - match[2].rm_so);
 
-	message = notmuch_database_find_message (notmuch, message_id);
-	if (message == NULL) {
-	    fprintf (stderr, "Warning: Cannot apply tags to missing message: %s\n",
-		     message_id);
+	status = notmuch_database_find_message (notmuch, message_id, &message);
+	if (status || message == NULL) {
+	    fprintf (stderr, "Warning: Cannot apply tags to %smessage: %s\n",
+		     message ? "" : "missing ", message_id);
+	    if (status)
+		fprintf (stderr, "%s\n",
+			 notmuch_status_to_string(status));
 	    goto NEXT_LINE;
 	}
 
-- 
1.7.6.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH v3 0/2] Better error handling
  2011-10-04  5:06                 ` [PATCH v3 0/2] Better error handling Ali Polatel
  2011-10-04  5:06                   ` [PATCH v3 1/2] lib: destroy message object after message removal Ali Polatel
  2011-10-04  5:06                   ` [PATCH v3 2/2] lib: make find_message{,by_filename) report errors Ali Polatel
@ 2011-10-04 10:43                   ` David Bremner
  2 siblings, 0 replies; 30+ messages in thread
From: David Bremner @ 2011-10-04 10:43 UTC (permalink / raw)
  To: Ali Polatel; +Cc: Ali Polatel, Notmuch Mailing List, Austin Clements

On Tue,  4 Oct 2011 08:06:07 +0300, Ali Polatel <polatel@gmail.com> wrote:
> From: Ali Polatel <alip@exherbo.org>
> 
> New set of patches addressing the issues in the mail
> "id:8739f9muhp.fsf@zancas.localnet"
> 
> You may also find the commits in my notmuch repository:
> git://github.com/alip/notmuch.git branch: find_message-v3
> 

I have pushed your revised version, thanks!

d

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Concerns regarding some library functions
  2011-09-29 20:15           ` Austin Clements
@ 2011-10-04 11:18             ` David Bremner
  2011-10-04 13:40               ` Tomi Ollila
  2011-10-04 19:36               ` libnotmuch SONAME bumped David Bremner
  0 siblings, 2 replies; 30+ messages in thread
From: David Bremner @ 2011-10-04 11:18 UTC (permalink / raw)
  To: Austin Clements; +Cc: notmuch

On Thu, 29 Sep 2011 16:15:36 -0400, Austin Clements <amdragon@MIT.EDU> wrote:
> With symbol versioning we'd still provide the old function (presumably
> re-implemented in terms of the new function).  Both would wind up in
> the .so and old binaries would still link against the old symbol.  It
> doesn't help that much once something gets recompiled; assuming the
> source isn't requesting a specific version of a symbol, it will try to
> use the latest version.
> 
> That, however, is about the extent of my knowledge on symbol
> versioning.  It's possible this simply doesn't work with symbols that
> don't already have a version; I'm not sure.

So I've pushed the ABI changes, making it more urgent to do something
about this.  At this point I'm inclined to bump the soname in order to
unbreak things, unless someone wants to come up with a convincing set of
patches to do the symbol versioning.

d

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: Concerns regarding some library functions
  2011-10-04 11:18             ` David Bremner
@ 2011-10-04 13:40               ` Tomi Ollila
  2011-10-04 19:36               ` libnotmuch SONAME bumped David Bremner
  1 sibling, 0 replies; 30+ messages in thread
From: Tomi Ollila @ 2011-10-04 13:40 UTC (permalink / raw)
  To: David Bremner; +Cc: notmuch, Austin Clements

On Tue 04 Oct 2011 14:18, David Bremner <david@tethera.net> writes:

>
> So I've pushed the ABI changes, making it more urgent to do something
> about this.  At this point I'm inclined to bump the soname in order to
> unbreak things, unless someone wants to come up with a convincing set of
> patches to do the symbol versioning.

Can symbol versioning be done with 'C' symbols ?

>
> d

Tomi

^ permalink raw reply	[flat|nested] 30+ messages in thread

* libnotmuch SONAME bumped 
  2011-10-04 11:18             ` David Bremner
  2011-10-04 13:40               ` Tomi Ollila
@ 2011-10-04 19:36               ` David Bremner
  1 sibling, 0 replies; 30+ messages in thread
From: David Bremner @ 2011-10-04 19:36 UTC (permalink / raw)
  To: notmuch

On Tue, 04 Oct 2011 08:18:21 -0300, David Bremner <david@tethera.net> wrote:
> So I've pushed the ABI changes, making it more urgent to do something
> about this.  At this point I'm inclined to bump the soname in order to
> unbreak things, unless someone wants to come up with a convincing set of
> patches to do the symbol versioning.

I just pushed a bump of the libnotmuch soname, and corresponding changes
to debian packaging.

Let me know if something broke

d

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH] lib: make find_message{,by_filename) report errors
  2011-10-01  8:12             ` Ali Polatel
@ 2011-10-05 13:42               ` Sebastian Spaeth
  0 siblings, 0 replies; 30+ messages in thread
From: Sebastian Spaeth @ 2011-10-05 13:42 UTC (permalink / raw)
  To: Ali Polatel, Austin Clements; +Cc: Notmuch Mailing List

[-- Attachment #1: Type: text/plain, Size: 142 bytes --]


The new API looks sane and much better to me.

+1, just give me plenty of time to catch up before releasing once this
goes in :-)

Sebastian

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2011-10-05 13:43 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-27 13:25 Concerns regarding some library functions Ali Polatel
2011-09-27 16:59 ` David Bremner
2011-09-27 22:46   ` Austin Clements
2011-09-28  7:53     ` Ali Polatel
2011-09-29 14:51       ` Austin Clements
2011-09-29 19:59         ` David Bremner
2011-09-29 20:15           ` Austin Clements
2011-10-04 11:18             ` David Bremner
2011-10-04 13:40               ` Tomi Ollila
2011-10-04 19:36               ` libnotmuch SONAME bumped David Bremner
2011-09-30  6:47         ` Concerns regarding some library functions Ali Polatel
2011-10-01  8:12           ` [PATCH] lib: make find_message{,by_filename) report errors Ali Polatel
2011-10-01  8:12             ` Ali Polatel
2011-10-05 13:42               ` Sebastian Spaeth
2011-10-03 16:49             ` [PATCH v1 0/1] " Ali Polatel
2011-10-03 16:49               ` [PATCH v1 1/1] " Ali Polatel
2011-10-03 17:43                 ` Austin Clements
2011-10-03 20:38                   ` [PATCH v1 1/1] lib: make find_message{, by_filename) " Ali Polatel
2011-10-03 20:40                     ` [PATCH v2 0/2] Better error handling Ali Polatel
2011-10-03 20:40                       ` [PATCH v2 1/2] lib: destroy message object after message removal Ali Polatel
2011-10-03 20:40                       ` [PATCH v2 2/2] lib: make find_message{,by_filename) report errors Ali Polatel
2011-10-03 20:53                       ` [PATCH v2 0/2] Better error handling Ali Polatel
2011-10-03 21:03                       ` Austin Clements
2011-10-04  1:10             ` [PATCH] lib: make find_message{,by_filename) report errors David Bremner
2011-10-04  5:00               ` Ali Polatel
2011-10-04  5:06                 ` [PATCH v3 0/2] Better error handling Ali Polatel
2011-10-04  5:06                   ` [PATCH v3 1/2] lib: destroy message object after message removal Ali Polatel
2011-10-04  5:06                   ` [PATCH v3 2/2] lib: make find_message{,by_filename) report errors Ali Polatel
2011-10-04 10:43                   ` [PATCH v3 0/2] Better error handling David Bremner
2011-09-28 15:42 ` Concerns regarding some library functions Sebastian Spaeth

Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).