Index: ChangeLog
===================================================================
--- ChangeLog	(revision 8509c08216ab7704fd2d8835a397f478b8e69402)
+++ ChangeLog	(revision 1fd0b25bc362ef6deee5d05e4558ce154f8c6f5c)
@@ -1,3 +1,11 @@
 $Id$
+
+1.2.2
+	Added the 'search' command.
+	'/' is a keybinding for 'search'
+	'?' is a keybinding for 'search -r'
+	Fixed stristr, which was completely broken
+	renamed owl_fmtext_ztext_stylestrip to owl_function_ztext_styletsrip
+	     and put it in functions.c
 
 1.2.1
Index: commands.c
===================================================================
--- commands.c	(revision f2e36b55e049ea4bedc8dfa6b96f20072e4edaa1)
+++ commands.c	(revision 1fd0b25bc362ef6deee5d05e4558ce154f8c6f5c)
@@ -497,4 +497,13 @@
 	      "returns the value of a variable",
 	      "getvar <varname>", ""),
+
+  OWLCMD_ARGS("search", owl_command_search, OWL_CTX_INTERACTIVE,
+	      "search messages for a particular string",
+	      "search [-r] [<string>]",
+	      "The search command will find messages that contain the\n"
+	      "specified string and move the cursor there.  If no string\n"
+	      "argument is supplied then the previous one is used.  By\n"
+	      "default searches are done fowards, if -r is used the search\n"
+	      "is performed backwards"),
 
   /****************************************************************/
@@ -1478,4 +1487,24 @@
 }
 
+char *owl_command_search(int argc, char **argv, char *buff) {
+  int direction;
+  char *buffstart;
+
+  direction=OWL_DIRECTION_DOWNWARDS;
+  buffstart=skiptokens(buff, 1);
+  if (argc>1 && !strcmp(argv[1], "-r")) {
+    direction=OWL_DIRECTION_UPWARDS;
+    buffstart=skiptokens(buff, 2);
+  }
+    
+  if (argc==1 || (argc==2 && !strcmp(argv[1], "-r"))) {
+    owl_function_search_continue(direction);
+  } else {
+    owl_function_search_start(buffstart, direction);
+  }
+  
+  return(NULL);
+}
+
 /*********************************************************************/
 /************************** EDIT SPECIFIC ****************************/
Index: fmtext.c
===================================================================
--- fmtext.c	(revision e1c4636a284110b07d889065fbb569709fa701d9)
+++ fmtext.c	(revision 1fd0b25bc362ef6deee5d05e4558ce154f8c6f5c)
@@ -19,4 +19,11 @@
   for (i=first; i<=last; i++) {
     f->fmbuff[i]=(unsigned char) attr;
+  }
+}
+
+void _owl_fmtext_add_attr(owl_fmtext *f, int attr, int first, int last) {
+  int i;
+  for (i=first; i<=last; i++) {
+    f->fmbuff[i]|=(unsigned char) attr;
   }
 }
@@ -332,17 +339,4 @@
 }
 
-/* strips formatting from ztext and returns the unformatted text. 
- * caller is responsible for freeing. */
-char *owl_fmtext_ztext_stylestrip(char *zt) {
-  owl_fmtext fm;
-  char *plaintext;
-
-  owl_fmtext_init_null(&fm);
-  owl_fmtext_append_ztext(&fm, zt);
-  plaintext = owl_fmtext_print_plain(&fm);
-  owl_fmtext_free(&fm);
-  return(plaintext);
-}
-
 
 void owl_fmtext_curs_waddstr(owl_fmtext *f, WINDOW *w) {
@@ -516,2 +510,35 @@
   memcpy(dst->colorbuff, src->colorbuff, src->textlen);
 }
+
+
+int owl_fmtext_search_and_highlight(owl_fmtext *f, char *string) {
+  /* highlight all instance of "string".  Return the number of
+   * instances found.  This is case insensitive. */
+
+  int found, len;
+  char *ptr1, *ptr2;
+
+  len=strlen(string);
+  found=0;
+  ptr1=f->textbuff;
+  while (ptr1-f->textbuff <= f->textlen) {
+    ptr2=stristr(ptr1, string);
+    if (!ptr2) return(found);
+
+    found++;
+    _owl_fmtext_add_attr(f, OWL_FMTEXT_ATTR_REVERSE,
+			 ptr2 - f->textbuff,
+			 ptr2 - f->textbuff + len - 1);
+
+    ptr1=ptr2+len;
+  }
+  return(found);
+}
+
+int owl_fmtext_search(owl_fmtext *f, char *string) {
+  /* return 1 if the string is found, 0 if not.  This is case
+   *  insensitive */
+
+  if (stristr(f->textbuff, string)) return(1);
+  return(0);
+}
Index: functions.c
===================================================================
--- functions.c	(revision f2e36b55e049ea4bedc8dfa6b96f20072e4edaa1)
+++ functions.c	(revision 1fd0b25bc362ef6deee5d05e4558ce154f8c6f5c)
@@ -1597,5 +1597,5 @@
 
   if (argc<2) {
-    owl_function_makemsg("Wrong number of arguments to the pexec command");
+    owl_function_makemsg("Wrong number of arguments to the exec command");
     return NULL;
   }
@@ -2182,5 +2182,5 @@
 /* TODO: implement for real */
 void owl_function_show_keymap(char *name) {
-  owl_fmtext  fm;
+  owl_fmtext fm;
   owl_keymap *km;
 
@@ -2198,5 +2198,5 @@
 
 void owl_function_help_for_command(char *cmdname) {
-  owl_fmtext   fm;
+  owl_fmtext fm;
 
   owl_fmtext_init_null(&fm);
@@ -2205,2 +2205,85 @@
   owl_fmtext_free(&fm);
 }
+
+void owl_function_search_start(char *string, int direction) {
+  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
+  owl_global_set_search_active(&g, string);
+  owl_function_search_helper(0, direction);
+}
+
+void owl_function_search_continue(int direction) {
+  /* direction is OWL_DIRECTION_DOWNWARDS or OWL_DIRECTION_UPWARDS */
+  owl_function_search_helper(1, direction);
+}
+
+void owl_function_search_helper(int mode, int direction) {
+  /* move to a message that contains the string.  If direction is
+   * OWL_DIRECTION_DOWNWARDS then search fowards, if direction is
+   * OWL_DIRECTION_UPWARDS then search backwards.
+   *
+   * If mode==0 then it will stay on the current message if it
+   * contains the string.
+   */
+
+  owl_view *v;
+  int viewsize, i, curmsg, start;
+  owl_message *m;
+
+  v=owl_global_get_current_view(&g);
+  viewsize=owl_view_get_size(v);
+  curmsg=owl_global_get_curmsg(&g);
+  
+  if (viewsize==0) {
+    owl_function_makemsg("No messages present");
+    return;
+  }
+
+  if (mode==0) {
+    start=curmsg;
+  } else if (direction==OWL_DIRECTION_DOWNWARDS) {
+    start=curmsg+1;
+  } else {
+    start=curmsg-1;
+  }
+
+  /* bounds check */
+  if (start>=viewsize || start<0) {
+    owl_function_makemsg("No further matches found");
+    return;
+  }
+
+  for (i=start; i<viewsize && i>=0;) {
+    m=owl_view_get_element(v, i);
+    if (owl_message_search(m, owl_global_get_search_string(&g))) {
+      owl_global_set_curmsg(&g, i);
+      owl_function_calculate_topmsg(direction);
+      owl_mainwin_redisplay(owl_global_get_mainwin(&g));
+      if (direction==OWL_DIRECTION_DOWNWARDS) {
+	owl_global_set_direction_downwards(&g);
+      } else {
+	owl_global_set_direction_upwards(&g);
+      }
+      return;
+    }
+    if (direction==OWL_DIRECTION_DOWNWARDS) {
+      i++;
+    } else {
+      i--;
+    }
+  }
+  owl_function_makemsg("No matches found");
+}
+
+
+/* strips formatting from ztext and returns the unformatted text. 
+ * caller is responsible for freeing. */
+char *owl_function_ztext_stylestrip(char *zt) {
+  owl_fmtext fm;
+  char *plaintext;
+
+  owl_fmtext_init_null(&fm);
+  owl_fmtext_append_ztext(&fm, zt);
+  plaintext = owl_fmtext_print_plain(&fm);
+  owl_fmtext_free(&fm);
+  return(plaintext);
+}
Index: global.c
===================================================================
--- global.c	(revision e1c4636a284110b07d889065fbb569709fa701d9)
+++ global.c	(revision 1fd0b25bc362ef6deee5d05e4558ce154f8c6f5c)
@@ -58,4 +58,6 @@
   g->colorpairs=COLOR_PAIRS;
   g->debug=OWL_DEBUG;
+  g->searchactive=0;
+  g->searchstring=NULL;
   g->starttime=time(NULL); /* assumes we call init only a start time */
   strcpy(g->buffercommand, "");
@@ -593,2 +595,22 @@
   return(0);
 }
+
+int owl_global_is_search_active(owl_global *g) {
+  if (g->searchactive) return(1);
+  return(0);
+}
+
+void owl_global_set_search_active(owl_global *g, char *string) {
+  g->searchactive=1;
+  if (g->searchstring != NULL) owl_free(g->searchstring);
+  g->searchstring=owl_strdup(string);
+}
+
+void owl_global_set_search_inactive(owl_global *g) {
+  g->searchactive=0;
+}
+
+char *owl_global_get_search_string(owl_global *g) {
+  if (g->searchstring==NULL) return("");
+  return(g->searchstring);
+}
Index: keys.c
===================================================================
--- keys.c	(revision f2e36b55e049ea4bedc8dfa6b96f20072e4edaa1)
+++ keys.c	(revision 1fd0b25bc362ef6deee5d05e4558ce154f8c6f5c)
@@ -203,4 +203,7 @@
   BIND_CMD("M-n", "smartnarrow",      "narrow to a view based on the current message");
   BIND_CMD("M-N", "smartnarrow -i",   "narrow to a view based on the current message, and consider instance pair");
+
+  BIND_CMD("/",   "start-command search ", "start a search command");
+  BIND_CMD("?",   "start-command search -r ", "start a revrerse search command");
 
   BIND_CMD("LEFT",   "recv:shiftleft", "");
Index: message.c
===================================================================
--- message.c	(revision e50cd5686952dc31173cfd67f7ebf1d6893945eb)
+++ message.c	(revision 1fd0b25bc362ef6deee5d05e4558ce154f8c6f5c)
@@ -460,4 +460,9 @@
     owl_fmtext_colorize(&b, color);
   }
+
+  if (owl_global_is_search_active(&g)) {
+    owl_fmtext_search_and_highlight(&b, owl_global_get_search_string(&g));
+  }
+      
   owl_fmtext_curs_waddstr(&b, win);
 
@@ -626,2 +631,8 @@
 }
 					
+int owl_message_search(owl_message *m, char *string) {
+  /* return 1 if the message contains "string", 0 otherwise.  This is
+   * case insensitive because the functions it uses are */
+
+  return (owl_fmtext_search(&(m->fmtext), string));
+}
Index: owl.h
===================================================================
--- owl.h	(revision 8509c08216ab7704fd2d8835a397f478b8e69402)
+++ owl.h	(revision 1fd0b25bc362ef6deee5d05e4558ce154f8c6f5c)
@@ -12,6 +12,6 @@
 static const char owl_h_fileIdent[] = "$Id$";
 
-#define OWL_VERSION         1.2.1
-#define OWL_VERSION_STRING "1.2.1"
+#define OWL_VERSION         1.2.2
+#define OWL_VERSION_STRING "1.2.2"
 
 #define OWL_DEBUG 0
@@ -384,4 +384,6 @@
   int hascolors;
   int colorpairs;
+  int searchactive;
+  char *searchstring;
   owl_filterelement fe_true;
   owl_filterelement fe_false;
Index: perlglue.xs
===================================================================
--- perlglue.xs	(revision e1c4636a284110b07d889065fbb569709fa701d9)
+++ perlglue.xs	(revision 1fd0b25bc362ef6deee5d05e4558ce154f8c6f5c)
@@ -9,5 +9,5 @@
 extern void owl_free(void *);
 extern int owl_zwrite_create_and_send_from_line(char *, char *);
-extern char *owl_fmtext_ztext_stylestrip(char *);
+extern char *owl_function_ztext_stylestrip(char *);
 
 MODULE = owl		PACKAGE = owl		
@@ -41,5 +41,5 @@
 		char *rv = NULL;
 	CODE:
-		rv = owl_fmtext_ztext_stylestrip(ztext);
+		rv = owl_function_ztext_stylestrip(ztext);
 		RETVAL = rv;
 	OUTPUT:
Index: util.c
===================================================================
--- util.c	(revision e50cd5686952dc31173cfd67f7ebf1d6893945eb)
+++ util.c	(revision 1fd0b25bc362ef6deee5d05e4558ce154f8c6f5c)
@@ -294,4 +294,10 @@
   downstr(y);
   ret=strstr(x, y);
+  if (ret==NULL) {
+    owl_free(x);
+    owl_free(y);
+    return(NULL);
+  }
+  ret=ret-x+a;
   owl_free(x);
   owl_free(y);
@@ -337,5 +343,5 @@
   int i;
   for (i=0; s[i]; i++) {
-    if (!isspace(s[i])) return(0);
+    if (!isspace((int) s[i])) return(0);
   }
   return(1);
