From e16b16e3c2e2673711d8337c0cbc530cd473f6d4 Mon Sep 17 00:00:00 2001
From: Sergey Poznyakoff <gray@Pirx.gnu.org.ua>
Date: Sat, 13 Jun 2009 09:19:10 +0300
Subject: [PATCH] NOMORE sockmap response code

* libsmmap/lookupaddr.c (sm_map_lookup_addr): Handle SM_E_NOMORE.
* libsmmap/sequence.c (sm_seq_lookup): Break on SM_E_NOMORE.
* libsmmap/sockmapimpl.c (sockmap_instance_lookup): Translate
"NOMORE" to SM_E_NOMORE.
* doc/README.tex: Document new response code.
---
 doc/README.tex         |   37 +++++++++++++++++++++++++++++++++++++
 libsmmap/lookupaddr.c  |   44 ++++++++++++++++++++++++++++++++++++++++++++
 libsmmap/sequence.c    |    4 ++--
 libsmmap/sockmapimpl.c |    3 +++
 4 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/doc/README.tex b/doc/README.tex
index 7a6a1ac..69c5f21 100644
--- a/doc/README.tex
+++ b/doc/README.tex
@@ -5111,6 +5111,7 @@ upper case words:
 \begin{tabular}{ll}
 {\tt OK}	& the key was found, result contains the looked up value \\
 {\tt NOTFOUND}	& the key was not found, the result is empty	\\
+{\tt NOMORE}    & the key was not found, stop further search    \\
 {\tt TEMP}	& a temporary failure occured	\\
 {\tt TIMEOUT}	& a timeout occured on the server side	\\
 {\tt PERM}	& a permanent failure occured	\\
@@ -5119,6 +5120,42 @@ upper case words:
 In case of errors (status {\tt TEMP}, {\tt TIMEOUT} or {\tt PERM})
 the result field may contain an explanatory message.
 
+The {\tt NOMORE} status indicates that the key has not been found and
+also instructs SMAR to stop any further searches using this key and its
+derivatives. 
+
+For example, consider lookups in the alias map. Suppose that the current
+alias map is configured as:
+
+\begin{verbatim}
+aliases {
+     name = aliasmap;
+     flags = { localpart, local_domains };
+}
+\end{verbatim}
+where {\tt aliasmap} is a socket map declared earlier in the
+configuration. This means that when looking for the key
+{\tt foo@bar.net}, SMAR will perform the following lookups 
+(see Section \ref{LookupOrders}):
+
+\begin{verbatim}
+aliases foo@bar.net
+aliases foo*@bar.net
+aliases foo
+\end{verbatim}
+
+Suppose that the alias {\tt foo@bar.net} does not exist, but the local
+alias {\tt foo} does exist. Now, when presented the lookup key {\tt
+foo@bar.net}, the socket map cannot simply return {\tt NOTFOUND},
+because then SMAR will go on searching until the search for
+{\tt foo} returns a false positive. In this case, the map should
+return {\tt NOMORE}. When returned this reply, SMAR discontinues
+further searches and acts as if {\tt NOTFOUND} was returned.
+
+The {\tt NOMORE} return works also in sequence map. If any of the maps
+in the sequence returns {\tt NOMORE}, the remaining maps are not
+tried.
+
 Example replies:
 
 \begin{verbatim}
diff --git a/libsmmap/lookupaddr.c b/libsmmap/lookupaddr.c
index 1b9d74d..30bb304 100644
--- a/libsmmap/lookupaddr.c
+++ b/libsmmap/lookupaddr.c
@@ -391,6 +391,10 @@ sm_map_lookup_addr(sm_map_P map, sm_str_P user, sm_str_P detail, sm_str_P domain
 				}
 				goto done;
 			}
+			if (SM_E_NOMORE == ret) {
+				ret = sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND);
+				goto done;
+			}
 		}
 
 		/* lookup with ++ (tag user delim + @ domain) */
@@ -431,6 +435,10 @@ sm_map_lookup_addr(sm_map_P map, sm_str_P user, sm_str_P detail, sm_str_P domain
 				}
 				goto done;
 			}
+			if (SM_E_NOMORE == ret) {
+				ret = sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND);
+				goto done;
+			}
 		}
 
 		/* lookup with +* (tag user delim * @ domain) */
@@ -471,6 +479,10 @@ sm_map_lookup_addr(sm_map_P map, sm_str_P user, sm_str_P detail, sm_str_P domain
 				}
 				goto done;
 			}
+			if (SM_E_NOMORE == ret) {
+				ret = sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND);
+				goto done;
+			}
 		}
 
 		/* lookup with * (tag user * @ domain) */
@@ -510,6 +522,10 @@ sm_map_lookup_addr(sm_map_P map, sm_str_P user, sm_str_P detail, sm_str_P domain
 				}
 				goto done;
 			}
+			if (SM_E_NOMORE == ret) {
+				ret = sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND);
+				goto done;
+			}
 		}
 
 		/*
@@ -561,6 +577,10 @@ sm_map_lookup_addr(sm_map_P map, sm_str_P user, sm_str_P detail, sm_str_P domain
 				}
 				goto done;
 			}
+			if (SM_E_NOMORE == ret) {
+				ret = sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND);
+				goto done;
+			}
 		}
 
 /*
@@ -608,6 +628,10 @@ sm_map_lookup_addr(sm_map_P map, sm_str_P user, sm_str_P detail, sm_str_P domain
 				}
 				goto done;
 			}
+			if (SM_E_NOMORE == ret) {
+				ret = sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND);
+				goto done;
+			}
 		}
 
 		if (domain != NULL && SMMAP_IS_LFL(flags, SMMAP_LFL_DOTSUBDOM)) {
@@ -656,6 +680,10 @@ sm_map_lookup_addr(sm_map_P map, sm_str_P user, sm_str_P detail, sm_str_P domain
 				goto done;
 			if (SM_SUCCESS == ret)
 				goto done;
+			if (SM_E_NOMORE == ret) {
+				ret = sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND);
+				goto done;
+			}
 		}
 
 		/* lookup with ++ (tag user delim +)*/
@@ -692,6 +720,10 @@ sm_map_lookup_addr(sm_map_P map, sm_str_P user, sm_str_P detail, sm_str_P domain
 				}
 				goto done;
 			}
+			if (SM_E_NOMORE == ret) {
+				ret = sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND);
+				goto done;
+			}
 		}
 
 		/* lookup with +* (tag user delim *) */
@@ -727,6 +759,10 @@ sm_map_lookup_addr(sm_map_P map, sm_str_P user, sm_str_P detail, sm_str_P domain
 				}
 				goto done;
 			}
+			if (SM_E_NOMORE == ret) {
+				ret = sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND);
+				goto done;
+			}
 		}
 
 		/* lookup with * (tag user *) */
@@ -762,6 +798,10 @@ sm_map_lookup_addr(sm_map_P map, sm_str_P user, sm_str_P detail, sm_str_P domain
 				}
 				goto done;
 			}
+			if (SM_E_NOMORE == ret) {
+				ret = sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND);
+				goto done;
+			}
 		}
 
 
@@ -803,6 +843,10 @@ sm_map_lookup_addr(sm_map_P map, sm_str_P user, sm_str_P detail, sm_str_P domain
 				}
 				goto done;
 			}
+			if (SM_E_NOMORE == ret) {
+				ret = sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND);
+				goto done;
+			}
 		}
 	}
 
diff --git a/libsmmap/sequence.c b/libsmmap/sequence.c
index 3f7abf8..4f135e0 100644
--- a/libsmmap/sequence.c
+++ b/libsmmap/sequence.c
@@ -386,8 +386,8 @@ sm_seq_lookup(sm_map_P map, uint32_t flags, sm_map_key_P key, sm_map_data_P data
 		if (NULL == maph)
 			return sm_error_perm(SM_EM_MAP, EINVAL);
 		ret = sm_map_lookup(maph, flags, key, data);
-		if (SM_SUCCESS == ret)
-			break;
+		if (SM_SUCCESS == ret || SM_E_NOMORE == ret) 
+			return ret;
 		if (sm_is_err(ret) && sm_is_temp_err(ret))
 			tempfail = ret;
 	}
diff --git a/libsmmap/sockmapimpl.c b/libsmmap/sockmapimpl.c
index 78fecba..5170c9c 100644
--- a/libsmmap/sockmapimpl.c
+++ b/libsmmap/sockmapimpl.c
@@ -273,6 +273,9 @@ sockmap_instance_lookup(sm_sockmap_P map, uint i, sm_str_P key, sm_str_P data)
 	else if (sm_streq(status, "NOTFOUND")) {
 		return sm_error_perm(SM_EM_MAP, SM_E_NOTFOUND);
 	}
+	else if (sm_streq(status, "NOMORE")) {
+		return SM_E_NOMORE;
+	} 
 	else {
 		if (sm_streq(status, "TEMP") || sm_streq(status, "TIMEOUT"))
 			ret = sm_error_temp(SM_EM_MAP, SM_E_TEMPMAP);
-- 
1.6.0

