+ let t = template_404 in
+ t#set "query" search_terms;
+ t#set "canonical_hostname" host.canonical_hostname;
+
+ (* This is a simplified version of the code in search.ml. *)
+ let have_results =
+ (* Get the keywords from the query string. *)
+ let keywords = Pcre.split ~rex:split_words search_terms in
+ let keywords =
+ List.filter (fun s -> not (string_is_whitespace s)) keywords in
+ let keywords = List.map String.lowercase keywords in
+
+ (* Turn the keywords into a tsearch2 ts_query string. *)
+ let tsquery = String.concat "&" keywords in
+
+ (* Search the titles first. *)
+ let rows =
+ PGSQL(dbh)
+ "select url, title, last_modified_date,
+ (lower (title) = lower ($search_terms)) as exact
+ from pages
+ where hostid = $hostid
+ and url is not null
+ and redirect is null
+ and title_description_fti @@ to_tsquery ('default', $tsquery)
+ order by exact desc, last_modified_date desc, title" in
+
+ let titles =
+ List.map (function
+ | (Some url, title, last_modified, _) ->
+ url, title, last_modified
+ | _ -> assert false) rows in
+
+ let have_titles = titles <> [] in
+ t#conditional "have_titles" have_titles;
+
+ (* Search the contents. *)
+ let rows =
+ PGSQL(dbh)
+ "select c.id, p.url, p.title, p.last_modified_date
+ from contents c, pages p
+ where c.pageid = p.id
+ and p.hostid = $hostid
+ and url is not null
+ and p.redirect is null
+ and c.content_fti @@ to_tsquery ('default', $tsquery)
+ order by p.last_modified_date desc, p.title
+ limit 50" in
+
+ let contents =
+ List.map (function
+ | (contentid, Some url, title, last_modified) ->
+ contentid, url, title, last_modified
+ | _ -> assert false) rows in
+
+ let have_contents = contents <> [] in
+ t#conditional "have_contents" have_contents;
+
+ (* Pull out the actual text which matched so we can generate a summary.
+ * XXX tsearch2 can actually do better than this by emboldening
+ * the text which maps.
+ *)
+ let content_map =
+ if contents = [] then []
+ else (
+ let rows =
+ let contentids =
+ List.map (fun (contentid, _,_,_) -> contentid) contents in
+ PGSQL(dbh)
+ "select id, sectionname, content from contents
+ where id in $@contentids" in
+ List.map (fun (id, sectionname, content) ->
+ id, (sectionname, content)) rows
+ ) in
+
+ (* Generate the final tables. *)
+ let table =
+ List.map (fun (url, title, last_modified) ->
+ let last_modified = printable_date last_modified in
+ [ "url", Template.VarString url;
+ "title", Template.VarString title;
+ "last_modified", Template.VarString last_modified ]
+ ) titles in
+ t#table "titles" table;
+
+ let table =
+ List.map
+ (fun (contentid, url, title, last_modified) ->
+ let sectionname, content = List.assoc contentid content_map in
+ let have_sectionname, sectionname =
+ match sectionname with
+ None -> false, ""
+ | Some sectionname -> true, sectionname in
+ let content =
+ truncate 160
+ (Wikilib.text_of_xhtml
+ (Wikilib.xhtml_of_content r dbh hostid content)) in
+ let linkname = linkname_of_sectionname sectionname in
+ let last_modified = printable_date last_modified in
+ [ "url", Template.VarString url;
+ "title", Template.VarString title;
+ "have_sectionname", Template.VarConditional have_sectionname;
+ "sectionname", Template.VarString sectionname;
+ "linkname", Template.VarString linkname;
+ "content", Template.VarString content;
+ "last_modified", Template.VarString last_modified ]
+ ) contents in
+ t#table "contents" table;
+
+ (* Do we have any results? *)
+ let have_results = have_titles || have_contents in
+ have_results in
+ t#conditional "have_results" have_results;
+
+ (* Deliver the rest of the page. *)
+ ignore (print_string r t#to_string)