Back to index

lightning-sunbird  0.9+nobinonly
nsRobotSink.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #include "nsIRobotSink.h"
00039 #include "nsIRobotSinkObserver.h"
00040 #include "nsIParserNode.h"
00041 #include "nsIParser.h"
00042 #include "nsString.h"
00043 #include "nsReadableUtils.h"
00044 #include "nsUnicharUtils.h"
00045 #include "nsIURL.h"
00046 #include "nsIURL.h"
00047 #include "nsIServiceManager.h"
00048 #include "nsIIOService.h"
00049 #include "nsNetCID.h"
00050 #include "nsCRT.h"
00051 #include "nsVoidArray.h"
00052 class nsIDocument;
00053 
00054 // TODO
00055 // - add in base tag support
00056 // - get links from other sources:
00057 //      - LINK tag
00058 //      - STYLE SRC
00059 //      - IMG SRC
00060 //      - LAYER SRC
00061 
00062 static NS_DEFINE_CID(kIOServiceCID, NS_IOSERVICE_CID);
00063 static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
00064 static NS_DEFINE_IID(kIHTMLContentSinkIID, NS_IHTML_CONTENT_SINK_IID);
00065 static NS_DEFINE_IID(kIRobotSinkIID, NS_IROBOTSINK_IID);
00066 
00067 class RobotSink : public nsIRobotSink {
00068 public:
00069   RobotSink();
00070   virtual ~RobotSink();
00071 
00072   NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
00073 
00074   // nsISupports
00075   NS_DECL_ISUPPORTS
00076 
00077   // nsIHTMLContentSink
00078   NS_IMETHOD SetTitle(const nsString& aValue);
00079   NS_IMETHOD OpenHTML(const nsIParserNode& aNode);
00080   NS_IMETHOD CloseHTML();
00081   NS_IMETHOD OpenHead(const nsIParserNode& aNode);
00082   NS_IMETHOD CloseHead();
00083   NS_IMETHOD OpenBody(const nsIParserNode& aNode);
00084   NS_IMETHOD CloseBody();
00085   NS_IMETHOD OpenForm(const nsIParserNode& aNode);
00086   NS_IMETHOD CloseForm();
00087   NS_IMETHOD OpenMap(const nsIParserNode& aNode);
00088   NS_IMETHOD CloseMap();
00089   NS_IMETHOD OpenFrameset(const nsIParserNode& aNode);
00090   NS_IMETHOD CloseFrameset();
00091   NS_IMETHOD IsEnabled(PRInt32 aTag, PRBool* aReturn) { return NS_OK; }
00092   NS_IMETHOD_(PRBool) IsFormOnStack() { return PR_FALSE; }
00093 
00094   NS_IMETHOD OpenContainer(const nsIParserNode& aNode);
00095   NS_IMETHOD CloseContainer(const nsHTMLTag aTag);
00096   NS_IMETHOD CloseTopmostContainer();
00097   NS_IMETHOD AddHeadContent(const nsIParserNode& aNode);
00098   NS_IMETHOD AddLeaf(const nsIParserNode& aNode);
00099   NS_IMETHOD AddComment(const nsIParserNode& aNode);
00100   NS_IMETHOD AddProcessingInstruction(const nsIParserNode& aNode);
00101   NS_IMETHOD AddDocTypeDecl(const nsIParserNode& aNode);
00102   NS_IMETHOD WillBuildModel(void) { return NS_OK; }
00103   NS_IMETHOD DidBuildModel(void) { return NS_OK; }
00104   NS_IMETHOD WillInterrupt(void) { return NS_OK; }
00105   NS_IMETHOD WillResume(void) { return NS_OK; }
00106   NS_IMETHOD SetParser(nsIParser* aParser) { return NS_OK; }
00107   virtual void FlushPendingNotifications(mozFlushType aType) { }
00108   NS_IMETHOD SetDocumentCharset(nsACString& aCharset) { return NS_OK; }
00109   virtual nsISupports *GetTarget() { return nsnull; }
00110   NS_IMETHOD WillProcessTokens(void) { return NS_OK; }
00111   NS_IMETHOD DidProcessTokens(void) { return NS_OK; }
00112   NS_IMETHOD WillProcessAToken(void) { return NS_OK; }
00113   NS_IMETHOD DidProcessAToken(void) { return NS_OK; }
00114   NS_IMETHOD NotifyTagObservers(nsIParserNode* aNode) { return NS_OK; }
00115 
00116   NS_IMETHOD BeginContext(PRInt32 aPosition){ return NS_OK; }
00117   NS_IMETHOD EndContext(PRInt32 aPosition){ return NS_OK; }
00118 
00119   // nsIRobotSink
00120   NS_IMETHOD Init(nsIURI* aDocumentURL);
00121   NS_IMETHOD AddObserver(nsIRobotSinkObserver* aObserver);
00122   NS_IMETHOD RemoveObserver(nsIRobotSinkObserver* aObserver);
00123 
00124   void ProcessLink(const nsString& aLink);
00125 
00126 protected:
00127   nsIURI* mDocumentURL;
00128   nsVoidArray mObservers;
00129 };
00130 
00131 nsresult NS_NewRobotSink(nsIRobotSink** aInstancePtrResult)
00132 {
00133   RobotSink* it = new RobotSink();
00134   if(it)
00135     return it->QueryInterface(kIRobotSinkIID, (void**) aInstancePtrResult);
00136   return NS_OK;
00137 }
00138 
00139 RobotSink::RobotSink()
00140 {
00141 }
00142 
00143 RobotSink::~RobotSink()
00144 {
00145   NS_IF_RELEASE(mDocumentURL);
00146   PRInt32 i, n = mObservers.Count();
00147   for (i = 0; i < n; ++i) {
00148     nsIRobotSinkObserver* cop = (nsIRobotSinkObserver*)mObservers.ElementAt(i);
00149     NS_RELEASE(cop);
00150   }
00151 }  
00152 
00153 NS_IMPL_ADDREF(RobotSink)
00154 
00155 NS_IMPL_RELEASE(RobotSink)
00156 
00157 NS_IMETHODIMP RobotSink::QueryInterface(REFNSIID aIID, void** aInstancePtr)
00158 {
00159   if (NULL == aInstancePtr) {
00160     return NS_ERROR_NULL_POINTER;
00161   }
00162   if (aIID.Equals(kIRobotSinkIID)) {
00163     *aInstancePtr = (void*) this;
00164     AddRef();
00165     return NS_OK;
00166   }
00167   if (aIID.Equals(kIHTMLContentSinkIID)) {
00168     *aInstancePtr = (void*) this;
00169     AddRef();
00170     return NS_OK;
00171   }
00172   if (aIID.Equals(kISupportsIID)) {
00173     *aInstancePtr = (void*) ((nsISupports*)this);
00174     AddRef();
00175     return NS_OK;
00176   }
00177   return NS_NOINTERFACE;
00178 }
00179 
00180 NS_IMETHODIMP RobotSink::SetTitle(const nsString& aValue)
00181 {
00182   return NS_OK;
00183 }
00184 
00185 NS_IMETHODIMP RobotSink::OpenHTML(const nsIParserNode& aNode)
00186 {
00187   return NS_OK;
00188 }
00189 
00190 NS_IMETHODIMP RobotSink::CloseHTML()
00191 {
00192   return NS_OK;
00193 }
00194 
00195 NS_IMETHODIMP RobotSink::OpenHead(const nsIParserNode& aNode)
00196 {
00197   return NS_OK;
00198 }
00199 
00200 NS_IMETHODIMP RobotSink::CloseHead()
00201 {
00202   return NS_OK;
00203 }
00204 
00205 NS_IMETHODIMP RobotSink::OpenBody(const nsIParserNode& aNode)
00206 {
00207   return NS_OK;
00208 }
00209 
00210 NS_IMETHODIMP RobotSink::CloseBody()
00211 {
00212   return NS_OK;
00213 }
00214 
00215 NS_IMETHODIMP RobotSink::OpenForm(const nsIParserNode& aNode)
00216 {
00217   return NS_OK;
00218 }
00219 
00220 NS_IMETHODIMP RobotSink::CloseForm()
00221 {
00222   return NS_OK;
00223 }
00224 
00225 NS_IMETHODIMP RobotSink::OpenMap(const nsIParserNode& aNode)
00226 {
00227   return NS_OK;
00228 }
00229 
00230 NS_IMETHODIMP RobotSink::CloseMap()
00231 {
00232   return NS_OK;
00233 }
00234 
00235 NS_IMETHODIMP RobotSink::OpenFrameset(const nsIParserNode& aNode)
00236 {
00237   return NS_OK;
00238 }
00239 
00240 NS_IMETHODIMP RobotSink::CloseFrameset()
00241 {
00242   return NS_OK;
00243 }
00244 
00245 NS_IMETHODIMP RobotSink::OpenContainer(const nsIParserNode& aNode)
00246 {
00247   nsAutoString tmp; tmp.Assign(aNode.GetText());
00248   ToLowerCase(tmp);
00249   if (tmp.EqualsLiteral("a")) {
00250     nsAutoString k, v;
00251     PRInt32 ac = aNode.GetAttributeCount();
00252     for (PRInt32 i = 0; i < ac; ++i) {
00253       // Get upper-cased key
00254       const nsAString& key = aNode.GetKeyAt(i);
00255       k.Assign(key);
00256       ToLowerCase(k);
00257       if (k.EqualsLiteral("href")) {
00258         // Get value and remove mandatory quotes
00259         v.Truncate();
00260         v.Append(aNode.GetValueAt(i));
00261         PRUnichar first = v.First();
00262         if ((first == '"') || (first == '\'')) {
00263           if (v.Last() == first) {
00264             v.Cut(0, 1);
00265             PRInt32 pos = v.Length() - 1;
00266             if (pos >= 0) {
00267               v.Cut(pos, 1);
00268             }
00269           } else {
00270             // Mismatched quotes - leave them in
00271           }
00272         }
00273         ProcessLink(v);
00274       }
00275     }
00276   }
00277   return NS_OK;
00278 }
00279 
00280 NS_IMETHODIMP RobotSink::CloseContainer(const nsHTMLTag aTag)
00281 {
00282   return NS_OK;
00283 }
00284 
00285 NS_IMETHODIMP RobotSink::CloseTopmostContainer()
00286 {
00287   return NS_OK;
00288 }
00289 
00290 NS_IMETHODIMP RobotSink::AddHeadContent(const nsIParserNode& aNode)
00291 {
00292   return NS_OK;
00293 }
00294 
00295 NS_IMETHODIMP RobotSink::AddLeaf(const nsIParserNode& aNode)
00296 {
00297   return NS_OK;
00298 }
00299 
00306 NS_IMETHODIMP RobotSink::AddComment(const nsIParserNode& aNode) {
00307   nsresult result= NS_OK;
00308   return result;
00309 }
00310 
00317 NS_IMETHODIMP RobotSink::AddProcessingInstruction(const nsIParserNode& aNode) {
00318   nsresult result= NS_OK;
00319   return result;
00320 }
00321 
00327 NS_IMETHODIMP
00328 RobotSink::AddDocTypeDecl(const nsIParserNode& aNode)
00329 {
00330   return NS_OK;
00331 }
00332 
00333 NS_IMETHODIMP RobotSink::Init(nsIURI* aDocumentURL)
00334 {
00335   NS_IF_RELEASE(mDocumentURL);
00336   mDocumentURL = aDocumentURL;
00337   NS_IF_ADDREF(aDocumentURL);
00338   return NS_OK;
00339 }
00340 
00341 NS_IMETHODIMP RobotSink::AddObserver(nsIRobotSinkObserver* aObserver)
00342 {
00343   if (mObservers.AppendElement(aObserver)) {
00344     NS_ADDREF(aObserver);
00345     return NS_OK;
00346   }
00347   return NS_ERROR_OUT_OF_MEMORY;
00348 }
00349 
00350 NS_IMETHODIMP RobotSink::RemoveObserver(nsIRobotSinkObserver* aObserver)
00351 {
00352   if (mObservers.RemoveElement(aObserver)) {
00353     NS_RELEASE(aObserver);
00354     return NS_OK;
00355   }
00356   //XXX return NS_ERROR_NOT_FOUND;
00357   return NS_OK;
00358 }
00359 
00360 void RobotSink::ProcessLink(const nsString& aLink)
00361 {
00362   nsAutoString absURLSpec; absURLSpec.Assign(aLink);
00363 
00364   // Make link absolute
00365   // XXX base tag handling
00366   nsIURI* docURL = mDocumentURL;
00367   if (nsnull != docURL) {
00368     nsIURI* absurl;
00369     nsresult rv;
00370     nsCOMPtr<nsIIOService> service(do_GetService(kIOServiceCID, &rv));
00371     if (NS_FAILED(rv)) return;
00372 
00373     nsIURI *uri = nsnull, *baseUri = nsnull;
00374 
00375     rv = mDocumentURL->QueryInterface(NS_GET_IID(nsIURI), (void**)&baseUri);
00376     if (NS_FAILED(rv)) return;
00377 
00378     NS_ConvertUCS2toUTF8 uriStr(aLink);
00379     rv = service->NewURI(uriStr, nsnull, baseUri, &uri);
00380     NS_RELEASE(baseUri);
00381     if (NS_FAILED(rv)) return;
00382 
00383     rv = uri->QueryInterface(NS_GET_IID(nsIURI), (void**)&absurl);
00384     NS_RELEASE(uri);
00385 
00386     if (NS_OK == rv) {
00387       absURLSpec.Truncate();
00388       nsCAutoString str;
00389       absurl->GetSpec(str);
00390       absURLSpec = NS_ConvertUTF8toUCS2(str);
00391     }
00392   }
00393 
00394   // Now give link to robot observers
00395   PRInt32 i, n = mObservers.Count();
00396   for (i = 0; i < n; ++i) {
00397     nsIRobotSinkObserver* cop = (nsIRobotSinkObserver*)mObservers.ElementAt(i);
00398     cop->ProcessLink(absURLSpec);
00399   }
00400 }
00401 
00402