Binary files /home/pabs/dl/gnut-0.4.14/src/cache.o and ./cache.o differ
Binary files /home/pabs/dl/gnut-0.4.14/src/cgi_parse.o and ./cgi_parse.o differ
diff -ur /home/pabs/dl/gnut-0.4.14/src/cli_input.c ./cli_input.c
--- /home/pabs/dl/gnut-0.4.14/src/cli_input.c	Thu Sep 21 10:25:25 2000
+++ ./cli_input.c	Sun Oct  1 16:38:38 2000
@@ -64,7 +64,8 @@
 int com_blacklist(char *), com_clear(char *), com_cls(char *),
   com_debug(char *), com_eval(char *), com_find(char *), com_get(char *),
   com_help(char *), com_hosts(char *), com_info(char *),
-  com_kill(char *), com_limit(char *), com_load(char *), com_log(char *),
+  com_kill(char *), com_lclear(char *), com_list(char *), 
+  com_limit(char *), com_load(char *), com_log(char *),
   com_monitor(char *), com_mpush(char *), com_mreply(char *),
   com_open(char  *), com_play(char *), com_player(char *),
   com_push(char *), com_quit(char *), com_response(char *), com_save(char *),
@@ -206,6 +207,21 @@
     limit 2000 2,10-12      - Limit transfers 2,10,11,12 to 2000 bytes
                               per second.
 "},
+  {"lclear",    com_lclear, "Clear search list.", "
+lclear GUID/\"string\" - Clear an active search if multi-searching is
+enabled (eg the \"multi_enable\" configuration flag is set).  lclear
+with no arguments clears all active searches and responses.  
+
+Examples:
+    lclear 4124          # removes the search with GUID 4124
+    lclear \"britney\"   # removes the search for \"britney\"
+    lclear \'spears\'    # removes the search for \"spears\"
+    lclear               # removes all searches and results
+"},
+  {"list",      com_list,   "List all current searches.", "
+list - List the active searches if multi-searching is enabled (eg 
+the \"multi_enable\" configuration flag is set).
+"},
   {"load",      com_load,   "Load a configuration file.", "
 load *file* - load a file containing gnut commands. This is a useful
 way to automate certain complex actions. For example, I have a file
@@ -236,6 +252,9 @@
 info. Bigger numbers produce more; anything above 2 is asking for
 trouble!
 "},
+  {"ls",    com_list,   "Synonym for 'list'.", "
+ls - synonym for 'list' (type 'help list')
+"},
   {"monitor",   com_monitor,"Monitor search requests.", "
 monitor *keywords* - Monitor incoming search queries. If arguments
 are supplied, they are used for a boolean AND match (ignoring case)
@@ -1184,6 +1203,7 @@
 int com_find(char *arg)
 {
   gnutella_packet *gpa;
+  int              maxs;
 
   if (recu_click(5)) {
 	if (arg) {
@@ -1200,7 +1220,19 @@
 	  
 	  gpa=gp_request_make(conf_get_str("mac"), arg, gc_ttl);
 	  conf_set_str_len("query_guid", gpa->gh.guid, 16);
-	  query_clear();
+
+	  if (conf_get_int("multi_enable"))	{
+	  	maxs = conf_get_int("max_searches");
+	  	if (maxs&&(gnut_search_count()+1>=maxs)) {
+	  		printf("Hit searches limit."
+	  		       "Removing oldest search string \"%s\".\n",
+	  		       current_searches->query);
+	  		gnut_search_remove(current_searches);
+	  	}
+	  	gnut_search_add(gpa->gh.guid, arg);
+	  } else {
+	  	query_clear();
+	  }
 	  
 	  /* Save a pointer to the query packet data */
 	  pthread_mutex_lock(&query_packet_mutex);
@@ -1230,6 +1262,68 @@
   return 0;
 }
 
+void clear_search_cb(GnutSearch *s, void *data)
+{
+	gnut_search_remove(s);
+	return;
+}
+
+char clear_guid_search_cb(GnutSearch *s, void *data)
+{
+	int   t, sum = 0;
+	for (t=0; t<14; t++) sum+=(unsigned char) s->guid[t];
+	return (sum==*((int*)data));
+}
+
+int com_lclear(char *arg)
+{
+	GnutSearch *search;
+	char       buf[1024] = "";
+	int        guid_hash = 0;
+	if (conf_get_int("multi_enable"))	{
+		if (!arg)	{
+			gnut_search_foreach(clear_search_cb, NULL);
+			query_clear();
+		} else {
+			if ((arg[0]=='\"'&&arg[strlen(arg)-1]=='\"') ||
+			    (arg[0]=='\''&&arg[strlen(arg)-1]=='\''))	{
+				memcpy(buf, arg+1, strlen(arg)-2);
+				buf[strlen(arg)-2] = 0;
+				search = gnut_search_find_by_query(buf);
+			} else {
+				guid_hash = atoi(arg);
+				search = gnut_search_find(clear_guid_search_cb, &guid_hash);
+			}
+			if (search)	{
+				printf("Removing search \"%s\".\n", search->query);
+				gnut_search_remove(search);
+			}
+		}
+	} else {
+		printf("Multisearch is disabled.\n");
+	}
+	return 0;
+}
+
+void list_search_cb(GnutSearch *s, void *data)
+{
+	int   t, sum = 0;
+	for (t=0; t<14; t++) sum+=(unsigned char) s->guid[t];
+	printf("%4d, %4d, \"%s\"\n", sum, s->responses, s->query);
+	return;
+}
+
+int com_list(char *arg)
+{
+	if (conf_get_int("multi_enable"))	{
+		printf("GUID,  Num, String\n");
+		gnut_search_foreach(list_search_cb, NULL);
+	} else {
+		printf("Multisearch is disabled.\n");
+	}
+	return 0;
+}
+
 /* Run the #update# command, which sends a PING packet causing update of
  * the host stats. This is the only place #gnut# generates a PING packet.
  * Since we get plenty of data from watching PONGs, it isn't really
@@ -1325,6 +1419,7 @@
   char ipstr[32];
   query_response **disp_qr_list = 0;
   int result_count=0;
+  int multi_enable = 0;
 
   /* regcomp is much more full featured than re_comp, so prefer it if both
    * are available. */
@@ -1341,9 +1436,13 @@
   t2=0;
 
   pthread_mutex_lock(&query_packet_mutex);
-  if (current_query_packet) {
+  multi_enable = conf_get_int("multi_enable");
+  if (!multi_enable&&current_query_packet) {
 	printf("Current query is '%s'\n",
 		   (((char *) (current_query_packet->data))+2));
+  } else if (multi_enable&&current_searches) {
+	printf("Current queries are (GUID, Responses, String): \n");
+	gnut_search_foreach(list_search_cb, NULL);
   }
   pthread_mutex_unlock(&query_packet_mutex);
   
Binary files /home/pabs/dl/gnut-0.4.14/src/cli_input.o and ./cli_input.o differ
diff -ur /home/pabs/dl/gnut-0.4.14/src/conf.c ./conf.c
--- /home/pabs/dl/gnut-0.4.14/src/conf.c	Mon Sep 18 13:03:37 2000
+++ ./conf.c	Sat Sep 30 22:45:14 2000
@@ -41,9 +41,11 @@
   {"max_responses",   "1000"},
   {"max_results",     "64"},
   {"max_uploads",     "10"},
+  {"max_searches",    "10"},
   {"min_cache_size",  "15"},
   {"min_connections", "4"},
   {"munge",           "1"},
+  {"multi_enable",    "0"},
   {"no_rfc_1597",     "0"},
   {"packet_stats",    "0"},
   {"paginate",        "1"},
Binary files /home/pabs/dl/gnut-0.4.14/src/conf.o and ./conf.o differ
Binary files /home/pabs/dl/gnut-0.4.14/src/gnut and ./gnut differ
Binary files /home/pabs/dl/gnut-0.4.14/src/gnut.o and ./gnut.o differ
diff -ur /home/pabs/dl/gnut-0.4.14/src/gnut_connection.c ./gnut_connection.c
--- /home/pabs/dl/gnut-0.4.14/src/gnut_connection.c	Fri Sep 15 15:17:06 2000
+++ ./gnut_connection.c	Sun Oct  1 15:00:25 2000
@@ -397,6 +397,11 @@
  * hashtable is executed, copying the data into the search results
  * list if matching data is found. */
 
+char name_tok_cb(GnutSearch *s, void *data)
+{
+	return is_match_tok(s->query, data, 1, 1);
+}
+
 /* do whatever processing is necessary */
 int connection_handle_packet(gnut_connection *gc, gnutella_packet *gpa)
 {
@@ -419,6 +424,8 @@
   uint32 pref, psize;
   route_entry *the_re;
   int no_drop;
+  GnutSearch *search = NULL;
+  int multi_enable;
   
   no_drop = 0;
   isnew=0;
@@ -844,13 +851,22 @@
 
 	/* If we have a query, look for matches. If strich_search is on, we
 	 * can match any query reply packet, getting more and quicker results */
-	if (current_query_packet) {
-	  int match_guid;
+	multi_enable = conf_get_int("multi_enable");
+	if ((multi_enable&&current_searches) || (!multi_enable&&current_query_packet)) {
+
+	  int match_guid = 0;
 
 	  /* We now only compare the first 14 bytes of the query GUID, because
 	   * the last two are used for subsequent invocations of the same query
 	   * over new GnutellaNet connections. */
-	  match_guid = (memcmp(conf_get_str("query_guid"), gpa->gh.guid, 14)==0);
+	  if (multi_enable) {
+	  	search = gnut_search_find_by_guid(gpa->gh.guid);
+	  	if (search) {
+	  		match_guid = 1;
+	  	}
+	  } else {
+	  	match_guid = (memcmp(conf_get_str("query_guid"), gpa->gh.guid, 14)==0);
+	  }
 	  if (match_guid || gc_strict_search) {
 		char *exts;
 		char *ourquery;
@@ -874,7 +890,14 @@
 		  accept = 0;
 		  if (gc_strict_search) {
 			/* Make sure this filename matches what we were searching for */
-			accept = is_match_tok(ourquery, grn->name, 1, 1);
+			if (multi_enable) {
+				search = gnut_search_find(name_tok_cb, grn->name);
+				if (search)	{
+					accept=1;
+				}
+			} else {
+				accept = is_match_tok(ourquery, grn->name, 1, 1); 
+			}
 		  } else if (match_guid) {
 			/* Strict search is off, but the packet matches our GUID so we
 			 * accept all results */
@@ -923,6 +946,7 @@
 			
 			query_add(grh->ip, grh->port, pref, speed, psize, grn->name,
 					  grs->guid);
+			if (multi_enable) search->responses++;
 		  }
 
 		  grn=(gnutella_results_name *)
Binary files /home/pabs/dl/gnut-0.4.14/src/gnut_connection.o and ./gnut_connection.o differ
Binary files /home/pabs/dl/gnut-0.4.14/src/gnut_http.o and ./gnut_http.o differ
Binary files /home/pabs/dl/gnut-0.4.14/src/gnut_lib.o and ./gnut_lib.o differ
Binary files /home/pabs/dl/gnut-0.4.14/src/gnut_net.o and ./gnut_net.o differ
diff -ur /home/pabs/dl/gnut-0.4.14/src/gnut_threads.c ./gnut_threads.c
--- /home/pabs/dl/gnut-0.4.14/src/gnut_threads.c	Fri Sep 15 16:20:45 2000
+++ ./gnut_threads.c	Sun Oct  1 15:01:41 2000
@@ -52,7 +52,136 @@
 int count_downloads=0;
 int count_uploads=0;
 
+int num_searches = 0;
+
 gnutella_packet * current_query_packet;
+GnutSearch      *current_searches;
+
+GnutSearch *gnut_search_add(char *guid, char *query)
+{
+	GnutSearch *t = NULL,
+	           *n = NULL;
+	int         i = 0;
+	if (!guid||!query)
+		return NULL;
+	if (gnut_search_find_by_query(query))	{
+		printf("Ignoring uplicate search string \"%s\"\n", query);
+		return NULL;
+	}
+	n = malloc(sizeof(GnutSearch));
+	if (!n)	{
+		return NULL;
+	} else {
+		n->guid = malloc(15);
+		for (i=0; i<14; i++)
+			n->guid[i] = guid[i];
+		n->guid[14] = 0;
+		/*n->guid = strdup(guid); <-- dunno if it's null terminated or not*/
+		n->query = strdup(query);
+		n->responses = 0;
+		n->next = NULL;
+	}
+
+	if (!current_searches)	{
+		current_searches = n;
+	} else {
+		for (t=current_searches; t->next; t=t->next);
+		t->next = n;
+	}
+	return n;
+}
+
+void gnut_search_remove(GnutSearch *s)
+{
+	GnutSearch *t = NULL;
+
+	if (!s)	
+		return;
+
+	if (current_searches==s)	{
+		current_searches = s->next;
+	} else {
+		for (t=current_searches; t; t=t->next)	{
+			if (t->next==s)	{
+				t->next = s->next;
+				break;
+			}
+		}
+	}
+
+	free(s->query);
+	free(s->guid);
+	free(s);
+	return;
+}
+
+void gnut_search_foreach(void (*cb)(GnutSearch *search,
+                                    void       *data),
+                         void  *data)
+{
+	GnutSearch *t = NULL,
+	           *next = NULL;
+
+	for (t=current_searches; t; t=next)	{
+		next = t->next;
+		cb(t,data);
+	}
+
+	return;
+}
+
+GnutSearch *gnut_search_find(char (*cb)(GnutSearch *search,
+                                        void       *data),
+                             void  *data)
+{
+	GnutSearch *t = NULL,
+	           *r = NULL,
+	           *next = NULL;
+
+	for (t=current_searches; t; t=next)	{
+		next = t->next;
+		if (cb(t,data))	{
+			r = t;
+			break;
+		}
+	}
+
+	return r;
+}
+
+char by_guid_cb(GnutSearch *s, void *data)
+{
+	char r = 0;
+	if (!memcmp(s->guid, data, 14))
+		r = 1;
+	return r;
+}
+
+GnutSearch *gnut_search_find_by_guid(char *guid)
+{
+	return gnut_search_find(by_guid_cb,guid);
+}
+
+char by_query_cb(GnutSearch *s, void *data)
+{
+	char r = 0;
+	if (!strcasecmp(s->query, data))
+		r = 1;
+	return r;
+}
+
+GnutSearch *gnut_search_find_by_query(char *query)
+{
+	return gnut_search_find(by_query_cb,query);
+}
+
+int gnut_search_count()
+{
+	GnutSearch *t = NULL;
+	int c = 0;
+	for (t=current_searches; t; t=t->next) c++;
+	return c;
+}
 
 int gnut_threads_num_downloads()
 {
diff -ur /home/pabs/dl/gnut-0.4.14/src/gnut_threads.h ./gnut_threads.h
--- /home/pabs/dl/gnut-0.4.14/src/gnut_threads.h	Fri Sep 15 13:25:02 2000
+++ ./gnut_threads.h	Sat Sep 30 21:28:28 2000
@@ -19,6 +19,7 @@
 
 typedef struct _incoming_arg incoming_arg;
 typedef struct _push_arg push_arg;
+typedef struct _GnutSearch GnutSearch;
 
 struct _incoming_arg {
   int s;
@@ -36,10 +37,29 @@
   time_t when;
 } bad_ip;
 
+struct _GnutSearch {
+	char       *guid;
+	char       *query;
+	int         responses;
+	GnutSearch *next;
+};
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+GnutSearch *gnut_search_add(char *guid, char *query);
+void        gnut_search_remove(GnutSearch *s);
+void        gnut_search_foreach(void (*cb)(GnutSearch *search,
+                                           void       *data),
+                                void  *data);
+GnutSearch *gnut_search_find(char (*cb)(GnutSearch *search,
+                                        void       *data),
+                             void  *data);
+GnutSearch *gnut_search_find_by_guid(char *guid);
+GnutSearch *gnut_search_find_by_query(char *query);
+int         gnut_search_count();
+
 int gnut_threads_num_incoming();
 int gnut_threads_num_outgoing();
 int gnut_threads_num_uploads();
@@ -53,6 +73,7 @@
 void * gnut_threads_push(void *arg);
 
 extern gnutella_packet * current_query_packet;
+extern GnutSearch *current_searches;
 
 #ifdef PTHREADS_DRAFT4
 extern pthread_mutex_t gc_list_mutex, send_mutex, _g_debug_mutex,
Binary files /home/pabs/dl/gnut-0.4.14/src/gnut_threads.o and ./gnut_threads.o differ
Binary files /home/pabs/dl/gnut-0.4.14/src/gnut_transfer.o and ./gnut_transfer.o differ
Binary files /home/pabs/dl/gnut-0.4.14/src/http_core.o and ./http_core.o differ
Binary files /home/pabs/dl/gnut-0.4.14/src/http_header.o and ./http_header.o differ
Binary files /home/pabs/dl/gnut-0.4.14/src/prompt.o and ./prompt.o differ

