Indexable is not marked _done_ until all the child indexables (including child of...
[beagle.git] / beagled / WebServices / WebBackEnd.cs
blob5dc2b9d1de59ed91f2cc5dc183e3bcc7a53f085a
1 //
2 // WebBackEnd.cs
3 //
4 // Copyright (C) 2005 Novell, Inc.
5 //
6 // Authors:
7 // Vijay K. Nanjundaswamy (knvijay@novell.com)
8 //
11 // Permission is hereby granted, free of charge, to any person obtaining a
12 // copy of this software and associated documentation files (the "Software"),
13 // to deal in the Software without restriction, including without limitation
14 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 // and/or sell copies of the Software, and to permit persons to whom the
16 // Software is furnished to do so, subject to the following conditions:
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 // DEALINGS IN THE SOFTWARE.
29 using System;
30 using System.Text;
31 using System.Collections;
32 using System.Diagnostics;
33 using System.Threading;
34 using System.Reflection;
35 using System.IO;
37 using System.Runtime.Remoting;
38 using System.Runtime.Remoting.Channels;
39 using System.Runtime.Remoting.Channels.Tcp;
41 using Beagle;
42 using Beagle.Util;
43 using BT = Beagle.Tile;
44 using Beagle.Daemon;
46 namespace Beagle.WebService {
48 [Serializable()]
49 public struct webArgs
51 public string sessId;
52 public string searchString;
53 public string searchSource;
54 public bool isLocalReq;
55 public bool globalSearch;
58 public class WebBackEnd: MarshalByRefObject{
60 static WebBackEnd instance = null;
61 static Logger log = Logger.Get ("WebBackEnd");
63 private Hashtable result;
64 private Hashtable sessionResp;
66 public WebBackEnd() {
67 result = Hashtable.Synchronized(new Hashtable());
68 sessionResp = Hashtable.Synchronized(new Hashtable());
71 ~WebBackEnd() {
72 result.Clear();
73 sessionResp.Clear();
76 public bool allowGlobalAccess {
77 get { return WebServiceBackEnd.web_global; }
80 public string HostName {
81 get { return WebServiceBackEnd.hostname; }
84 static TcpChannel tch1 = null;
85 public static void init()
87 if (instance == null) {
88 instance = new WebBackEnd();
90 if (tch1 == null) {
92 tch1 = new TcpChannel(8347);
94 //Register TCP Channel Listener
95 ChannelServices.RegisterChannel(tch1);
97 WellKnownServiceTypeEntry WKSTE =
98 new WellKnownServiceTypeEntry(typeof(WebBackEnd),
99 "WebBackEnd.rem", WellKnownObjectMode.Singleton);
100 RemotingConfiguration.ApplicationName="beagled";
101 RemotingConfiguration.RegisterWellKnownServiceType(WKSTE);
106 public static void cleanup()
108 if (tch1 != null) {
109 tch1.StopListening(null);
110 ChannelServices.UnregisterChannel(tch1);
111 tch1 = null;
114 instance = null;
117 void OnHitsAdded (QueryResult qres, ICollection hits)
119 if (result.Contains(qres)) {
121 Resp resp = ((Resp) result[qres]);
122 BT.SimpleRootTile root = resp.resultPair.rootTile;
123 ArrayList hitsCopy = resp.resultPair.hitsCopy;
125 lock (root) {
126 if (resp.isLocalReq) {
127 root.Add(hits);
128 lock (hitsCopy.SyncRoot)
129 hitsCopy.AddRange(hits);
131 else {
132 foreach (Hit h in hits)
133 if (h.UriAsString.StartsWith(NetworkedBeagle.BeagleNetPrefix) ||
134 WebServiceBackEnd.AccessFilter.FilterHit(h)) {
135 root.Add(h);
136 lock (hitsCopy.SyncRoot)
137 hitsCopy.Add(h);
144 void removeUris(ArrayList res, ICollection uris)
146 foreach(Uri u in uris)
147 foreach(Hit h in res)
148 if (h.Uri.Equals (u) && h.Uri.Fragment == u.Fragment) {
149 lock (res.SyncRoot) {
150 res.Remove(h);
152 break;
156 void OnHitsSubtracted (QueryResult qres, ICollection uris)
158 if (result.Contains(qres)) {
159 BT.SimpleRootTile root = ((Resp) result[qres]).resultPair.rootTile;
160 lock (root) {
161 root.Subtract (uris);
162 removeUris(((Resp) result[qres]).resultPair.hitsCopy, uris);
167 void OnFinished (QueryResult qres)
169 if (result.Contains(qres))
170 log.Info("WebBackEnd:OnFinished() - Got {0} results from beagled QueryDriver", ((Resp) result[qres]).resultPair.rootTile.HitCollection.NumResults);
172 DetachQueryResult(qres);
175 void OnCancelled (QueryResult qres)
177 DetachQueryResult(qres);
180 private void AttachQueryResult (QueryResult qres, Resp resp)
182 if (qres != null) {
184 qres.HitsAddedEvent += OnHitsAdded;
185 qres.HitsSubtractedEvent += OnHitsSubtracted;
186 qres.FinishedEvent += OnFinished;
187 qres.CancelledEvent += OnCancelled;
189 result.Add(qres, resp);
193 private void DetachQueryResult (QueryResult qres)
195 if (qres != null) {
197 if (result.Contains(qres))
199 Resp resp = ((Resp) result[qres]);
200 ArrayList hitsCopy = resp.resultPair.hitsCopy;
201 if (hitsCopy != null)
202 hitsCopy.Sort();
204 resp.bufferContext.maxDisplayed = 0;
206 result.Remove(qres);
209 qres.HitsAddedEvent -= OnHitsAdded;
210 qres.HitsSubtractedEvent -= OnHitsSubtracted;
211 qres.FinishedEvent -= OnFinished;
212 qres.CancelledEvent -= OnCancelled;
214 qres.Dispose ();
218 const string NO_RESULTS = "No results.";
220 private string getResultsLabel(BT.SimpleRootTile root)
222 string label;
223 if (root.HitCollection.NumResults == 0)
224 label = NO_RESULTS;
225 else if (root.HitCollection.FirstDisplayed == 0)
226 label = String.Format ("<b>{0} results of {1}</b> are shown.",
227 root.HitCollection.LastDisplayed + 1,
228 root.HitCollection.NumResults);
229 else
230 label = String.Format ("Results <b>{0} through {1} of {2}</b> are shown.",
231 root.HitCollection.FirstDisplayed + 1,
232 root.HitCollection.LastDisplayed + 1,
233 root.HitCollection.NumResults);
234 return label;
237 public bool canForward(string sessId)
239 Resp resp = (Resp) sessionResp[sessId];
240 if (resp == null)
241 return false;
243 BT.SimpleRootTile root = resp.resultPair.rootTile;
244 return (root != null)? root.HitCollection.CanPageForward:false;
247 public string doForward(string sessId)
249 Resp resp = (Resp) sessionResp[sessId];
251 if (!canForward(sessId) || (resp == null))
252 return NO_RESULTS;
254 BT.SimpleRootTile root = resp.resultPair.rootTile;
255 if (root != null) {
256 lock (root) {
257 root.HitCollection.PageForward ();
259 bufferRenderContext bctx = resp.bufferContext;
260 bctx.init();
261 root.Render(bctx);
262 return (getResultsLabel(root) + (resp.isLocalReq ? bctx.buffer:bctx.bufferForExternalQuery));
266 return NO_RESULTS;
269 public bool canBack(string sessId)
271 Resp resp = (Resp) sessionResp[sessId];
272 if (resp == null)
273 return false;
275 BT.SimpleRootTile root = resp.resultPair.rootTile;
276 return (root != null) ? root.HitCollection.CanPageBack:false;
279 public string doBack(string sessId)
281 Resp resp = (Resp) sessionResp[sessId];
282 if (!canBack(sessId) || (resp == null))
283 return NO_RESULTS;
285 BT.SimpleRootTile root = resp.resultPair.rootTile;
286 if (root != null) {
288 lock (root) {
289 root.HitCollection.PageBack();
291 bufferRenderContext bctx = resp.bufferContext;
292 bctx.init();
293 root.Render(bctx);
294 return (getResultsLabel(root) + (resp.isLocalReq ? bctx.buffer:bctx.bufferForExternalQuery));
298 return NO_RESULTS;
301 public bool NetworkBeagleActive
303 get {return NetworkedBeagle.NetBeagleListActive;}
306 public string doQuery(webArgs wargs)
308 if (wargs.sessId == null || wargs.searchString == null || wargs.searchString == "")
309 return NO_RESULTS;
311 log.Debug("WebBackEnd: Got Search String: " + wargs.searchString);
313 Query query = new Query();
314 query.AddText (wargs.searchString);
315 if (wargs.searchSource != null && wargs.searchSource != "")
317 query.AddSource(wargs.searchSource);
318 query.AddDomain(QueryDomain.System);
320 else
321 query.AddDomain (wargs.globalSearch ? QueryDomain.Global:QueryDomain.System);
323 QueryResult qres = new QueryResult ();
325 //Note: QueryDriver.DoQuery() local invocation is used.
326 //The root tile is used only for adding hits and generating html.
327 BT.SimpleRootTile root = new BT.SimpleRootTile ();
328 root.Query = query;
329 //root.SetSource (searchSource); Do not SetSource on root!
331 ResultPair rp = new ResultPair(root);
332 bufferRenderContext bctx = new bufferRenderContext(rp);
333 Resp resp = new Resp(rp, bctx, wargs.isLocalReq);
335 AttachQueryResult (qres, resp);
337 //Add sessionId-Resp mapping
338 if (sessionResp.Contains(wargs.sessId))
339 sessionResp[wargs.sessId] = resp;
340 else
341 sessionResp.Add(wargs.sessId, resp);
343 log.Info("WebBackEnd: Starting Query for string \"{0}\"", wargs.searchString);
345 QueryDriver.DoQueryLocal (query, qres);
347 //Wait only till we have enough results to display
348 while ((result.Contains(qres)) &&
349 (root.HitCollection.NumResults < 10))
350 Thread.Sleep(100);
352 if (root.HitCollection.IsEmpty)
353 return NO_RESULTS;
355 lock (root) {
356 root.Render(bctx);
357 return (getResultsLabel(root) + (wargs.isLocalReq ? bctx.buffer:bctx.bufferForExternalQuery));
361 public void dispatchAction (string sessId, string actionString)
363 string tile_id = null, action = null;
364 bool actionDone = false;
366 //if (actionString.StartsWith ("dynaction:")) {
368 bufferRenderContext b = ((Resp)sessionResp[sessId]).bufferContext;
369 if (b != null)
370 actionDone = b.DoAction(actionString);
373 if (actionDone)
374 return;
376 if (actionString.StartsWith ("action:")) {
378 int pos1 = "action:".Length;
379 int pos2 = actionString.IndexOf ("!");
381 if (pos2 <= 0)
382 return;
384 tile_id = actionString.Substring (pos1, pos2 - pos1);
385 action = actionString.Substring (pos2 + 1);
387 log.Debug("WebBackEnd tile_id: {0}, action: {1}", tile_id, action);
389 BT.Tile t = ((Resp)sessionResp[sessId]).GetTile (tile_id);
391 if (t == null)
392 return;
394 MethodInfo info = t.GetType().GetMethod (action,
395 BindingFlags.Public | BindingFlags.NonPublic |
396 BindingFlags.Instance, null,
397 CallingConventions.Any, new Type[] {}, null);
399 if (info == null) {
400 log.Warn ("WebBackEnd:dispatchAction couldn't find method called {0}", action);
401 return;
404 object[] attrs = info.GetCustomAttributes (false);
405 foreach (object attr in attrs) {
406 if (attr is BT.TileActionAttribute) {
407 info.Invoke (t, null);
408 return;
411 log.Warn ("WebBackEnd:dispatchAction {0} does not have the TileAction attribute", t);
414 string command = null;
415 string commandArgs = null;
417 if (actionString.StartsWith ("http://") || actionString.StartsWith ("file://")) {
418 command = "gnome-open";
419 commandArgs = "'" + actionString + "'";
421 else if (actionString.StartsWith ("mailto:")) {
422 command = "evolution";
423 commandArgs = actionString;
426 if (command != null) {
427 Process p = new Process ();
428 p.StartInfo.UseShellExecute = false;
429 p.StartInfo.FileName = command;
430 if (commandArgs != null)
431 //if (args != null)
432 p.StartInfo.Arguments = commandArgs;
433 try {
435 p.Start ();
437 catch { }
441 //////////////////////////////////////////////////////////////////////////
443 private class ResultPair {
444 private BT.SimpleRootTile _rootTile;
445 private ArrayList _hitsCopy;
447 public ResultPair(BT.SimpleRootTile rootTile) {
448 this._rootTile = rootTile;
449 _hitsCopy = ArrayList.Synchronized(new ArrayList());
452 public BT.SimpleRootTile rootTile {
453 get { return _rootTile; }
456 public ArrayList hitsCopy {
457 get { return _hitsCopy; }
461 private class Resp {
463 private ResultPair _rp;
464 private bufferRenderContext bufCtx = null;
465 private bool _localRequest;
467 private Hashtable tileTab = null;
469 public Resp(ResultPair rp, bufferRenderContext bCtx, bool isLocalReq)
471 this._rp = rp;
472 this.bufCtx = bCtx;
473 this._localRequest = isLocalReq;
475 this.tileTab = bCtx.table;
478 public ResultPair resultPair {
479 get { return _rp; }
481 public bufferRenderContext bufferContext {
482 get { return bufCtx; }
484 public bool isLocalReq {
485 get { return _localRequest; }
488 public BT.Tile GetTile (string key)
490 if (key == "")
491 return resultPair.rootTile;
493 return (Beagle.Tile.Tile) tileTab[key];
497 //////////////////////////////////////////////////////////////////////////
498 private class bufferRenderContext : BT.TileRenderContext {
500 private ResultPair _rp;
501 private Hashtable tileTable = null;
502 private Hashtable actionTable = null;
503 int actionId = 1;
505 private System.Text.StringBuilder sb;
506 private bool renderStylesDone = false;
508 public bufferRenderContext (ResultPair rp)
510 this._rp = rp;
511 this.tileTable = Hashtable.Synchronized(new Hashtable());
512 this.actionTable = new Hashtable ();
513 init();
516 public string buffer {
517 get { return sb.ToString(); }
520 public Hashtable table {
521 get { return tileTable; }
524 public string bufferForExternalQuery {
526 get {
527 //Substitute "action:_tile_id!Open" with "http://host:port/beagle?xxxx"
528 string s;
529 string[] list = sb.ToString().Split('\"');
530 for (int i = 0; i < list.Length; i++) {
532 s = list[i];
533 if (s.StartsWith("action") && s.EndsWith("!Open")) {
535 string[] s1 = s.Split(':');
536 if (s1.Length > 1) {
537 string[] s2 = s1[1].Split('!');
538 if (s2.Length > 1) {
539 BT.Tile t = (BT.Tile) table[s2[0]];
540 list[i] = WebServiceBackEnd.AccessFilter.TranslateHit(t.Hit);
541 t.Uri = new Uri(list[i]);
546 return String.Join ("\"", list);
550 public void init()
552 lock (this) {
553 sb = new StringBuilder(4096);
554 renderStylesDone = false;
555 tileTable.Clear();
556 ClearActions();
557 tileTable[_rp.rootTile.UniqueKey] = _rp.rootTile;
560 /////////////////////////////////////////////////
561 public void ClearActions ()
563 actionTable.Clear();
564 actionId = 1;
567 private string AddAction (BT.TileActionHandler handler)
569 if (handler == null)
570 return "dynaction:NULL";
571 string key = "dynaction:" + actionId.ToString ();
572 ++actionId;
573 actionTable [key] = handler;
574 return key;
577 public bool DoAction (string key)
579 BT.TileActionHandler handler = (BT.TileActionHandler) actionTable [key];
580 if (handler != null) {
581 handler ();
582 return true;
584 return false;
586 /////////////////////////////////////////////////
588 override public void Write (string markup)
590 sb.Append(markup);
593 override public void Link (string label,
594 BT.TileActionHandler handler)
596 string key = AddAction (handler);
597 Write ("<a href=\"{0}\">{1}</a>", key, label);
600 override public void Tile (BT.Tile tile)
602 tileTable [tile.UniqueKey] = tile;
604 if (!renderStylesDone) {
605 //KNV: Using static_stylesheet for now. Replace with TileCanvas logic later:
606 Write(static_stylesheet);
608 Write ("<style type=\"text/css\" media=\"screen\">");
609 TileCanvas.RenderStyles (this);
610 Write ("</style>");
612 renderStylesDone = true;
615 if (tile != null) {
617 if (tile is BT.TileHitCollection)
618 PrefetchSnippetsForNetworkHits((BT.TileHitCollection)tile);
620 tile.Render (this);
623 /////////////////////////////////////////////////
624 // Code to scan forward through result set & prefetch/cache Snippets for Network Hits
626 public int maxDisplayed = 0;
627 const int MAX_HIT_IDS_PER_REQ = 20; //Max no. of hits snippets to seek at a time
628 const int MAX_HITS_AHEAD = 40; //No. of hits ahead of lastDisplayed to scan
630 private bool tenHits = false; //Flag to do Prefetch check only every 10 hits
632 private void PrefetchSnippetsForNetworkHits(BT.TileHitCollection thc)
634 int lastDisplayed = 0;
636 if (maxDisplayed != 0)
637 lastDisplayed = thc.LastDisplayed + 1;
639 //We have cached snippets for network hits upto maxDisplayed
640 if (lastDisplayed < maxDisplayed)
641 return;
643 maxDisplayed = thc.LastDisplayed + 1;
645 //Do Prefetch check once every ten hits
646 tenHits = !tenHits;
647 if (!tenHits)
648 return;
650 if (lastDisplayed < thc.NumResults) {
652 int limit = 0;
653 ArrayList networkHits = new ArrayList();
655 if ((thc.NumResults - lastDisplayed) > MAX_HITS_AHEAD)
656 limit = lastDisplayed + MAX_HITS_AHEAD;
657 else
658 limit = thc.NumResults;
660 ArrayList hits = _rp.hitsCopy;
661 lock (hits.SyncRoot) {
663 if (limit > hits.Count)
664 limit = hits.Count;
666 log.Debug("PrefetchSnippets: Scanning result set for Network Hits from {0} to {1}", lastDisplayed, limit);
668 //Get all NetworkHits with snippets field not initialized:
669 for (int si = lastDisplayed; si < limit ; si++)
671 if ((hits[si] is NetworkHit) && (((NetworkHit)hits[si]).snippet == null))
672 networkHits.Add((NetworkHit)hits[si]);
676 log.Debug("PrefetchSnippets: Found {0} NetworkHits without snippets", networkHits.Count);
678 while (networkHits.Count > 0) {
680 ArrayList nwHitsPerNode = new ArrayList();
681 string hostnamePort = GetHostnamePort((NetworkHit)networkHits[0]);
683 //Gather NetworkHits from a specific target Networked Beagle
684 foreach (NetworkHit nh in networkHits)
686 string hnp = GetHostnamePort(nh);
687 if (hnp == null)
688 continue;
690 if (hnp.Equals(hostnamePort)) {
692 if (nwHitsPerNode.Count < MAX_HIT_IDS_PER_REQ)
693 nwHitsPerNode.Add(nh);
694 else
695 break;
699 //Remove NetworkHits for this Networked Beagle
700 int i = networkHits.Count;
701 while (--i >= 0) {
703 string hnp = GetHostnamePort((NetworkHit)networkHits[i]);
704 if ((hnp == null) || hnp.Equals(hostnamePort))
705 networkHits.RemoveAt(i);
708 if (nwHitsPerNode.Count > 0)
710 string[] f3 = hostnamePort.Split(':');
711 if (f3.Length < 2)
713 log.Warn("PrefetchSnippets: Invalid format netBeagle URI in NetworkHit");
714 continue;
716 BeagleWebService wsp = new BeagleWebService(f3[0], f3[1]);
718 string searchToken = GetSearchToken((NetworkHit)nwHitsPerNode[0]);
720 if (searchToken.Equals("beagle")) //Check if it is Older version of Beagle networking
721 searchToken = null;
723 if (searchToken != null) {
725 int[] hitHashCodes = new int [nwHitsPerNode.Count];
726 for (int j = 0; j < hitHashCodes.Length; j++)
727 hitHashCodes[j] = ((NetContext) ((NetworkHit)nwHitsPerNode[j]).context).hashCode;
729 log.Debug("PrefetchSnippets: Invoking GetSnippets on {0} for {1} hits", wsp.Hostname, nwHitsPerNode.Count);
731 GetSnippetsRequest sreq = new GetSnippetsRequest();
732 sreq.searchToken = searchToken;
733 sreq.hitHashCodes = hitHashCodes;
735 ReqContext2 rc = new ReqContext2(wsp, nwHitsPerNode, thc);
736 wsp.BeginGetSnippets(sreq, PrefetchSnippetsResponseHandler, rc);
739 //Signal change in TileHitCollection due to addition of snippets:
740 //_rp.rootTile.HitCollection.ClearSources(null);
742 } //end while
743 } //end if
746 private static void PrefetchSnippetsResponseHandler(IAsyncResult ar)
748 ReqContext2 rc = (ReqContext2)ar.AsyncState;
750 ArrayList nwHits = rc.GetNwHits;
751 BeagleWebService wsp = rc.GetProxy;
755 Beagle.Daemon.HitSnippet[] hslist = wsp.EndGetSnippets(ar);
757 int j = 0;
758 if (hslist.Length > 0)
760 log.Debug("PrefetchSnippetsResponseHandler: Got {0} snippet responses from {1}", hslist.Length, wsp.Hostname);
762 foreach (Beagle.Daemon.HitSnippet hs in hslist) {
764 int i, hitHashCode;
765 string snippet;
767 try {
768 hitHashCode = hs.hashCode;
769 snippet = hs.snippet;
771 catch (Exception ex2)
773 log.Warn ("Exception in WebBackEnd: PrefetchSnippetsResponseHandler(), while getting snippet from {1}\n Reason: {2} ", wsp.Hostname + ":" + wsp.Port, ex2.Message);
774 continue;
777 if (snippet.StartsWith(WebServiceBackEnd.InvalidHitSnippetError))
778 continue;
780 for (i = 0; i < nwHits.Count; i++)
781 if ( ((NetContext) ((NetworkHit)nwHits[i]).context).hashCode == hitHashCode) {
783 ((NetworkHit)nwHits[i]).snippet = snippet;
784 //log.Debug("\nPrefetchSnippetsResponseHandler: URI" + j++ + "=" + ((NetworkHit)nwHits[i]).UriAsString + "\n Snippet=" + snippet);
785 break;
788 if (i < nwHits.Count)
789 nwHits.RemoveAt(i);
790 } //end foreach
793 catch (Exception ex) {
794 log.Error ("Exception in WebBackEnd: PrefetchSnippetsResponseHandler() - {0} - for {1} ", ex.Message, wsp.Hostname + ":" + wsp.Port);
797 if (nwHits.Count > 0) {
798 //Possible Error in getting snippets for these hitIds
799 log.Warn("WebBackEnd/PrefetchSnippetsResponseHandler(): Didn't get Snippets for some network Hits");
801 foreach (NetworkHit nh in nwHits)
802 nh.snippet = "";
805 //Signal change in TileHitCollection due to addition of snippets:
806 rc.GetHitCollection.ClearSources(null);
809 private class ReqContext2 {
811 BT.TileHitCollection _thc;
812 BeagleWebService _wsp;
813 ArrayList _nwHits;
815 public ReqContext2(BeagleWebService wsp, ArrayList nwHits, BT.TileHitCollection thc)
817 this._thc = thc;
818 this._wsp = wsp;
819 this._nwHits = nwHits;
822 public BT.TileHitCollection GetHitCollection {
823 get { return _thc; }
826 public BeagleWebService GetProxy {
827 get { return _wsp; }
830 public ArrayList GetNwHits {
831 get { return _nwHits; }
836 private string GetSearchToken(NetworkHit nh)
838 if (nh == null)
839 return null;
841 string netUri = nh.UriAsString;
843 //netbeagle://164.99.153.134:8888/searchToken?http:///....
844 string[] f1, f2 = netUri.Split('?');
845 if (f2.Length > 1) {
846 f1 = f2[0].Split ('/');
847 if (f1.Length > 1)
848 return (f1[f1.Length - 1]);
850 return null;
853 private string GetHostnamePort(NetworkHit nh)
855 if (nh == null)
856 return null;
858 string netUri = nh.UriAsString;
860 //netbeagle://164.99.153.134:8888/searchToken?http:///....
861 string[] f1, f2 = netUri.Split('?');
862 if (f2.Length > 1) {
863 f1 = f2[0].Split ('/');
864 if (f1.Length > 1)
865 return (f1[2]);
867 return null;
870 //////////////////////////////////////////////////////////////////////////
872 //string static_stylesheet = "<style type=\"text/css\" media=\"screen\"> body, html { background: white; margin: 0; padding: 0; font-family: Sans, Segoe, Trebuchet MS, Lucida, Sans-Serif; text-align: left; line-height: 1.5em; } a, a:visited { text-decoration: none; color: #2b5a8a; } a:hover { text-decoration: underline; } img { border: 0px; } table { width: 100%; border-collapse: collapse; font-size: 10px; } tr { border-bottom: 1px dotted #999999; } tr:hover { background: #f5f5f5; } tr:hover .icon { background-color: #ddddd0; } td { padding: 6px; } td.icon { background-color: #eeeee0; min-height: 80px; width: 1%; min-width: 80px; text-align: center; vertical-align: top; padding: 12px; } .icon img { max-width: 60px; padding: 4px; } .icon img[src$='.jpg'], img[src$='.jpeg'], img[src*='.thumbnails'] {// max-width: 48px; border: 1px dotted #bbb; // padding: 4px; background: #f9f9f9; } td.content { padding-left: 12px; vertical-align: top; } #hilight { background-color: #ffee66; color: #000000; padding-left: 2px; padding-right: 2px; margin-left: -2px; margin-right: -2px; } .name {font-size: 1.3em; font-weight: bold; color: black; } .date { font-size: 1em; color: black; margin-bottom: 0.6em; margin-top: 0.2em; margin-left: 16px; } .snippet {font-size: 1em; color: gray; margin-left: 16px; } .url {font-size: 1em; color: #008200; margin-left: 16px; } ul {margin-left: 16px; padding: 0px; clear: both; } .actions { font-size: 1em; } .actions li { float: left; display: block; vertical-align: middle; padding: 0; padding-left: 20px; padding-right: 12px; background: url(file:///opt/gnome/share/icons/hicolor/16x16/stock/navigation/stock_right.png) no-repeat; min-height: 16px; -moz-opacity: 0.5; } tr:hover .actions li { -moz-opacity: 1.0; } #phone { background: url(file:///opt/gnome/share/icons/hicolor/16x16/stock/generic/stock_landline-phone.png) no-repeat; } #email { background: url(file:///opt/gnome/share/icons/hicolor/16x16/stock/net/stock_mail.png) no-repeat; } #email-forward { background: url(file:///opt/gnome/share/icons/hicolor/16x16/stock/net/stock_mail-forward.png) no-repeat; } #email-reply { background: url(file:///opt/gnome/share/icons/hicolor/16x16/stock/net/stock_mail-reply.png) no-repeat; } #message { background: url(file:///opt/gnome/share/icons/hicolor/16x16/apps/im-yahoo.png) no-repeat; } #reveal { background: url(file:///opt/gnome/share/icons/hicolor/16x16/stock/io/stock_open.png) no-repeat; } td.footer { text-align: right; border-bottom: solid 1px white; } </style>";
873 string static_stylesheet = "<style type=\"text/css\" media=\"screen\"> body, html { background: white; margin: 0; padding: 0; font-family: Arial KOI-8, Segoe, Trebuchet MS, Lucida, Sans-Serif; text-align: left; line-height: 1.5em; } a, a:visited { text-decoration: none; color: #2b5a8a; } a:hover { text-decoration: underline; } img { border: 0px; } table { width: 100%; border-collapse: collapse; font-size: 11px; } tr { border-bottom: 1px dotted #999999; } tr:hover { background: #f5f5f5; } tr:hover .icon { background-color: #ddddd0; } td { padding: 6px; } td.icon { background-color: #eeeee0; min-height: 80px; width: 1%; min-width: 80px; text-align: center; vertical-align: top; padding: 12px; } .icon img { max-width: 60px; padding: 4px; } .icon img[src$='.jpg'], img[src$='.jpeg'], img[src*='.thumbnails'] { // max-width: 48px; border: 1px dotted #bbb; // padding: 4px; background: #f9f9f9; } td.content { padding-left: 12px; vertical-align: top; } #hilight { background-color: #ffee66; color: #000000; padding-left: 2px; padding-right: 2px; margin-left: -2px; margin-right: -2px; } .name { font-size: 1.3em; font-weight: bold; color: black; } .date { font-size: 1em; color: black; margin-bottom: 0.6em; margin-top: 0.2em; margin-left:16px; } .snippet { font-size: 1em; color: gray; margin-left: 16px; } .url { font-size: 1em; color: #008200; margin-left: 16px; } ul { margin-left: 16px; padding: 0px; clear: both; } .actions { font-size: 1em; } .actions li { float: left; display: block; vertical-align: middle; padding: 0; padding-left: 20px; padding-right: 12px; background: url(file:///opt/gnome/share/icons/hicolor/16x16/stock/navigation/stock_right.png) no-repeat; min-height: 16px; -moz-opacity: 0.5; } tr:hover .actions li { -moz-opacity: 1.0;} #phone { background: url(file:///opt/gnome/share/icons/hicolor/16x16/stock/generic/stock_landline-phone.png) no-repeat; } #email { background: url(file:///opt/gnome/share/icons/hicolor/16x16/stock/net/stock_mail.png) no-repeat; } #email-forward { background: url(file:///opt/gnome/share/icons/hicolor/16x16/stock/net/stock_mail-forward.png) no-repeat; } #email-reply { background: url(file:///opt/gnome/share/icons/hicolor/16x16/stock/net/stock_mail-reply.png) no-repeat; } #message { background: url(file:///opt/gnome/share/icons/hicolor/16x16/apps/im-yahoo.png) no-repeat; } #reveal { background: url(file:///opt/gnome/share/icons/hicolor/16x16/stock/io/stock_open.png) no-repeat; } td.footer { text-align: right; border-bottom: solid 1px white; } </style>";