Indexable is not marked _done_ until all the child indexables (including child of...
[beagle.git] / beagled / WebServices / WebFrontEnd.cs
blob1723ad51883c4811145bfd0d92f0af3c02f09a2f
1 //
2 // WebFrontEnd.cs
3 //
4 // Copyright (C) 2005 Novell, Inc.
5 //
6 // Authors:
7 // Vijay K. Nanjundaswamy (knvijay@novell.com)
8 //
10 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal in the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 // DEALINGS IN THE SOFTWARE.
29 using System;
30 using System.Threading;
31 using System.Collections;
32 using System.Collections.Specialized;
33 using System.Diagnostics;
35 using System.Web;
36 using System.Web.UI;
37 using System.Web.UI.HtmlControls;
38 using System.Web.UI.WebControls;
40 using System.Runtime.Remoting;
41 using System.Runtime.Remoting.Channels;
42 using System.Runtime.Remoting.Channels.Tcp;
44 using Beagle.Util;
45 using Beagle.Daemon;
46 using Beagle.WebService;
48 namespace WebService_CodeBehind {
50 public class BeagleWebPage: System.Web.UI.Page {
52 private static string HeaderMsg = "BeagleWebInterface: ";
54 private static string enableSessionMsg = HeaderMsg + "Please <b>enable web session tracking</b> (via Cookies or modified URL) ! <p> BeagleWeb access <i>cannot</i> function without session identification information";
56 private static string localReqOnlyMsg = HeaderMsg + "Beagle web service unavailable or access restricted to local address only !";
58 protected HtmlForm SearchForm;
59 protected Label Output, TitleLabel;
60 protected TextBox SearchBox;
61 protected DropDownList sourceList;
62 protected CheckBox GlobalSearchCheckBox;
63 protected Button Search, Forward, Back;
65 const string NO_RESULTS = "No results.";
67 protected void Page_Load(Object o, EventArgs e) {
69 //note: this web-form relies on availability of Session information either through
70 // cookies or modified Url. It won't work if persistent session id is not available.
72 string sessId = Session.SessionID;
73 Output.Visible = Back.Visible = Forward.Visible = true;
75 if (Session["ResultsOnDisplay"] != null
76 && ((string)Session["ResultsOnDisplay"]).StartsWith(HeaderMsg + NO_RESULTS)) {
77 Back.Visible = Forward.Visible = false;
80 string actionString = null;
81 bool queryStringProcessed = false;
83 string reqUrl = Request.Url.ToString();
84 int index = reqUrl.IndexOf(".aspx?");
85 if (index > 0)
86 actionString = reqUrl.Substring(index + ".aspx?".Length);
88 if (!IsPostBack) {
89 //HTTP GET request
90 if (actionString == null) {
91 //HTTP Get without any query string
92 if (Session["ResultsOnDisplay"] == null) {
93 //First access
94 Output.Visible = false;
95 Back.Visible = Forward.Visible = false;
97 int index1 = reqUrl.IndexOf(".aspx");
98 if ((index1 > 0) && (index1 + ".aspx".Length < reqUrl.Length))
99 Session["InitialReqUrl"] = reqUrl.Substring(0, index1 + ".aspx".Length);
100 else
101 Session["InitialReqUrl"] = reqUrl;
103 Session["SearchString"] = "";
104 Session["Source"] = "Anywhere";
105 sourceList.SelectedValue = "Anywhere";
107 if (Session["GlobalCheckBox"] == null) {
108 //GlobalSearchCheckBox.Visible = ((string)Session["Source"]).Equals("Anywhere");
109 //By default, NetBeagleSearch checkbox is checked for local access & unchecked for ext. access
110 GlobalSearchCheckBox.Checked = isLocalReq()? true:false;
111 Session["GlobalCheckBox"] = GlobalSearchCheckBox.Checked;
114 else {
116 //Redirected from Tile-Action invocation, restore Results
117 SearchBox.Text = (string) Session["SearchString"];
118 sourceList.SelectedValue = (string) Session["Source"];
120 Output.Text = (string) Session["ResultsOnDisplay"];
121 WebBackEnd remoteObj = (WebBackEnd) Session["RemObj"];
122 if (remoteObj != null) {
123 Back.Enabled = remoteObj.canBack(sessId);
124 Forward.Enabled = remoteObj.canForward(sessId);
125 GlobalSearchCheckBox.Visible = (remoteObj.NetworkBeagleActive) && (sourceList.SelectedValue.Equals("Anywhere"));
127 if (!isLocalReq() && (((string)TitleLabel.Text).IndexOf("host") < 0))
128 TitleLabel.Text += " from host: " + remoteObj.HostName;
130 GlobalSearchCheckBox.Checked = (bool) Session["GlobalCheckBox"];
133 else { //HTTP-Get request with query string:
134 //Initial web query initiated via HTTP Get (firefox search bar):
136 string searchString = null;
137 NameValueCollection nvc = Request.QueryString;
139 if ((nvc != null) && (nvc.Count != 0) &&
140 ((searchString = nvc["text"]) != null )) {
142 SearchBox.Text = searchString;
143 Session["SearchString"] = searchString;
145 string source = null;
146 if ((source = nvc["source"]) != null)
148 switch (source.ToLower()) {
150 case "files": sourceList.SelectedValue = "Files";
151 break;
152 case "addressbook": sourceList.SelectedValue = "Contact";
153 break;
154 case "mail" : sourceList.SelectedValue = "MailMessage";
155 break;
156 case "web" : sourceList.SelectedValue = "WebHistory";
157 break;
158 case "chats": sourceList.SelectedValue = "IMLog";
159 break;
160 case "anywhere":
161 default: sourceList.SelectedValue = "Anywhere";
162 break;
164 else
165 sourceList.SelectedValue = "Anywhere";
167 Session["Source"] = sourceList.SelectedValue;
168 GlobalSearchCheckBox.Visible = ((string)Session["Source"]).Equals("Anywhere");
169 //By default, NetBeagleSearch checkbox is checked for local access & unchecked for ext. access
170 GlobalSearchCheckBox.Checked = isLocalReq()? true:false;
171 Session["GlobalCheckBox"] = GlobalSearchCheckBox.Checked;
173 if (Session["ResultsOnDisplay"] == null) {
175 int index2 = reqUrl.IndexOf(".aspx");
176 if ((index2 > 0) && (index2 + ".aspx".Length < reqUrl.Length))
177 Session["InitialReqUrl"] = reqUrl.Substring(0, index2 + ".aspx".Length);
178 else
179 Session["InitialReqUrl"] = reqUrl;
182 queryStringProcessed = true;
184 Search_Click(o, e);
186 //Redirect client to initial Beagle webaccess URL:
187 Response.Redirect((string)Session["InitialReqUrl"]);
189 } //end else for if (actionString == null)
190 } //end if (!IsPostBack)
192 //Process Tile!Action HTTP-Get request, if user has clicked on one:
193 if (actionString != null && !queryStringProcessed) {
195 WebBackEnd remoteObj = (WebBackEnd) Session["RemObj"];
197 if (remoteObj != null) {
198 if (isLocalReq())
199 remoteObj.dispatchAction(sessId, actionString);
201 else {
202 Output.Text = enableSessionMsg;
203 Back.Visible = Forward.Visible = GlobalSearchCheckBox.Visible = false;
204 return;
207 //Redirect client to initial Beagle webaccess URL:
208 Response.Redirect((string)Session["InitialReqUrl"]);
212 private bool isLocalReq() {
213 //tells whether request originated from local machine
214 return Request.Url.IsLoopback;
217 private string convertUrls(string buf)
219 //Replace specific actions in URL's
220 string buf1 = buf.Replace("href=\"action:", "href=\"" + Session["InitialReqUrl"] + "?action:");
221 string buf2 = buf1.Replace("href=\"dynaction:", "href=\"" + Session["InitialReqUrl"] + "?dynaction:");
223 string initUrl = (string) Session["InitialReqUrl"];
225 //Get the initial part of url: i.e. http://localhost:8888/beagle
226 int i = initUrl.LastIndexOf('/');
227 string UrlPrefix = initUrl.Substring(0, i);
229 //Check if initial url was http://localhost:8888/search.aspx & add a trailing "/"
230 if (UrlPrefix.EndsWith("beagle"))
231 UrlPrefix += "/";
232 else
233 UrlPrefix += "/beagle/";
235 string[] list = buf2.Split('\"');
236 for (int k = 0; k < list.Length; k++) {
238 if (list[k].Length <= 0)
239 continue;
241 list[k] = list[k].Replace("file://" + ExternalStringsHack.KdePrefix, UrlPrefix + "kde3");
242 list[k] = list[k].Replace("file://" + ExternalStringsHack.GnomePrefix, UrlPrefix + "gnome");
243 list[k] = list[k].Replace("file://" + ExternalStringsHack.Prefix, UrlPrefix + "local");
246 string imgId = "0001";
247 ArrayList prList = new ArrayList();
248 const string ImgFilePrefix = "img src=\"file://";
250 list = (String.Join ("\"", list)).Split('<');
251 for (int n = 0; n < list.Length; n++) {
253 if (list[n].StartsWith(ImgFilePrefix)) {
255 string[] l = list[n].Split('\"');
256 //l[1] now contains "file:///home/usr/folder/xyz.png"
257 string path = l[1].Remove(0, 7); //remove "file://" prefix
258 string[] l2 = path.Split('.');
259 if (l2.Length < 2)
260 continue;
262 string[] guid = (System.Guid.NewGuid().ToString()).Split('-');
263 if (guid.Length > 1)
264 imgId = guid[guid.Length - 1]; //last 12 chars of guid
266 string linkName = "i" + imgId + "." + l2[l2.Length - 1]; //like ixxxxxx.png, izzzzzz.jpg
268 try {
269 Process pr = new Process ();
270 pr.StartInfo.UseShellExecute = true;
271 pr.StartInfo.FileName = "ln";
272 pr.StartInfo.Arguments = " -sf " + path + " " + PathFinder.StorageDir + "/img/" + linkName;
274 pr.Start ();
276 prList.Add(pr);
278 catch (Exception e)
280 Console.WriteLine("Error creating symbolic link for image file");
283 //Replace l[1] with "http://localhost:8888/beagle/img/i1.png
284 l[1] = UrlPrefix + "img/" + linkName;
285 list[n] = String.Join ("\"", l);
289 //Wait for link ops to complete
290 if (prList.Count > 0)
291 foreach (Process pr in prList) {
292 pr.WaitForExit();
293 pr.Close();
294 pr.Dispose();
297 return String.Join ("<", list);
300 protected void Search_Click(object o, EventArgs e) {
302 //if (IsPostBack && Session.IsNewSession)
303 if (Session["InitialReqUrl"] == null) {
304 Output.Text = enableSessionMsg;
305 Back.Visible = Forward.Visible = GlobalSearchCheckBox.Visible = false;
306 return;
309 if (SearchBox.Text.Trim() == "") {
310 Output.Text = HeaderMsg + NO_RESULTS;
311 Back.Visible = Forward.Visible = false;
313 Session["SearchString"] = SearchBox.Text;
314 Session["ResultsOnDisplay"] = Output.Text;
315 Session["GlobalCheckBox"] = GlobalSearchCheckBox.Checked;
316 return;
319 string searchSrc = sourceList.SelectedItem.Value;
320 if (searchSrc.Equals("Anywhere"))
321 searchSrc = null;
323 remoteChannel.Register();
325 WebBackEnd remoteObj = (WebBackEnd) Session["RemObj"];
326 if (remoteObj == null) {
327 remoteObj = new WebBackEnd();
330 if ( (remoteObj == null) || !(remoteObj.allowGlobalAccess || isLocalReq())) {
332 Output.Text = localReqOnlyMsg;
333 Back.Visible = Forward.Visible = GlobalSearchCheckBox.Visible = false;
334 sourceList.Enabled = SearchBox.Enabled = Search.Enabled = false;
335 return;
338 if (!isLocalReq() && (((string)TitleLabel.Text).IndexOf("host") < 0))
339 TitleLabel.Text += " from host: " + remoteObj.HostName;
341 //Show check-box only if we have one or more NetworkedBeagle nodes configured:
342 bool showGlobalCheckBox = (remoteObj.NetworkBeagleActive) && (searchSrc == null);
344 //Setup arguments for WebBackEnd:doQuery()
345 webArgs wargs = new webArgs();
346 wargs.sessId = Session.SessionID;
347 wargs.searchString = SearchBox.Text;
348 wargs.searchSource = searchSrc;
349 wargs.isLocalReq = isLocalReq();
350 wargs.globalSearch = showGlobalCheckBox?GlobalSearchCheckBox.Checked:false;
352 string response = "";
353 try {
354 response = remoteObj.doQuery(wargs);
356 catch (Exception ex)
358 response = "Exception in WebBackEnd:doQuery method\n";
359 Console.WriteLine("WebFrontEnd: Caught Exception in WebBackEnd:doQuery()\n" + ex.Message);
362 if (response.StartsWith(NO_RESULTS)) {
363 Output.Text = HeaderMsg + response;
364 Back.Visible = Forward.Visible = false;
366 else {
367 Output.Text = HeaderMsg + convertUrls(response);
368 Back.Enabled = remoteObj.canBack(Session.SessionID);
369 Forward.Enabled = remoteObj.canForward(Session.SessionID);
372 GlobalSearchCheckBox.Visible = showGlobalCheckBox;
373 Session["GlobalCheckBox"] = GlobalSearchCheckBox.Checked;
374 Session["RemObj"] = remoteObj;
375 Session["ResultsOnDisplay"] = Output.Text;
376 Session["SearchString"] = SearchBox.Text;
377 Session["Source"] = searchSrc;
380 protected void Back_Click(object o, EventArgs e) {
382 WebBackEnd remoteObj = (WebBackEnd) Session["RemObj"];
383 //if (IsPostBack && HttpContext.Current.Session.IsNewSession)
384 if (remoteObj == null) {
385 Output.Text = enableSessionMsg;
386 Back.Visible = Forward.Visible = GlobalSearchCheckBox.Visible = false;
387 return;
390 if ( (remoteObj == null) || !(remoteObj.allowGlobalAccess || isLocalReq())) {
392 Output.Text = localReqOnlyMsg;
393 Back.Visible = Forward.Visible = GlobalSearchCheckBox.Visible = false;
394 sourceList.Enabled = SearchBox.Enabled = Search.Enabled = false;
395 return;
398 string sessId = Session.SessionID;
400 SearchBox.Text = (string) Session["SearchString"];
401 sourceList.SelectedValue = (string) Session["Source"];
403 //if (remoteObj == null) { Output.Text = NO_RESULTS; return; }
405 string response = "";
406 try {
407 response = convertUrls(remoteObj.doBack(sessId));
409 catch (Exception ex)
411 response = "Exception in WebBackEnd:doBack method\n";
412 Console.WriteLine("WebFrontEnd: Caught Exception in WebBackEnd:doBack()\n" + ex.Message);
415 Session["ResultsOnDisplay"] = Output.Text = HeaderMsg + response;
417 GlobalSearchCheckBox.Checked = (bool)Session["GlobalCheckBox"];
418 Back.Enabled = (remoteObj != null) && (remoteObj.canBack(sessId));
419 Forward.Enabled = (remoteObj != null) && (remoteObj.canForward(sessId));
422 protected void Forward_Click(object o, EventArgs e) {
424 WebBackEnd remoteObj = (WebBackEnd) Session["RemObj"];
425 //if (IsPostBack && HttpContext.Current.Session.IsNewSession)
426 if (remoteObj == null) {
427 Output.Text = enableSessionMsg;
428 Back.Visible = Forward.Visible = GlobalSearchCheckBox.Visible = false;
429 return;
432 if ( (remoteObj == null) || !(remoteObj.allowGlobalAccess || isLocalReq())) {
434 Output.Text = localReqOnlyMsg;
435 Back.Visible = Forward.Visible = GlobalSearchCheckBox.Visible = false;
436 sourceList.Enabled = SearchBox.Enabled = Search.Enabled = false;
437 return;
440 string sessId = Session.SessionID;
441 SearchBox.Text = (string) Session["SearchString"];
442 sourceList.SelectedValue = (string) Session["Source"];
444 //if (remoteObj == null) { Output.Text = NO_RESULTS; return; }
445 string response = "";
446 try {
447 response = convertUrls(remoteObj.doForward(sessId));
449 catch (Exception ex)
451 response = "Exception in WebBackEnd:doForward method\n";
452 Console.WriteLine("WebFrontEnd: Caught Exception in WebBackEnd:doForward()\n" + ex.Message);
455 Session["ResultsOnDisplay"] = Output.Text = HeaderMsg + response;
457 GlobalSearchCheckBox.Checked = (bool)Session["GlobalCheckBox"];
458 Back.Enabled = (remoteObj != null) && (remoteObj.canBack(sessId));
459 Forward.Enabled = (remoteObj != null) && (remoteObj.canForward(sessId));