Back to index

lightning-sunbird  0.9+nobinonly
nsRelatedLinksHandler.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; c-file-style: "stroustrup" -*- */
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 
00039 /*
00040 
00041   Implementation for a Related Links RDF data store.
00042 
00043  */
00044 
00045 #include "nsRelatedLinksHandlerImpl.h"
00046 #include "nsCRT.h"
00047 #include "nsEnumeratorUtils.h"
00048 #include "nsIInputStream.h"
00049 #include "nsIRDFNode.h"
00050 #include "nsIRDFObserver.h"
00051 #include "nsIRDFPurgeableDataSource.h"
00052 #include "nsIServiceManager.h"
00053 #include "nsIStreamListener.h"
00054 #include "nsIURL.h"
00055 #include "nsNetUtil.h"
00056 #include "nsIInputStream.h"
00057 #include "nsIPref.h"
00058 #include "nsRDFCID.h"
00059 #include "nsVoidArray.h"
00060 #include "nsXPIDLString.h"
00061 #include "nsReadableUtils.h"
00062 #include "nsUnicharUtils.h"
00063 #include "nscore.h"
00064 #include "plhash.h"
00065 #include "plstr.h"
00066 #include "prio.h"
00067 #include "prmem.h"
00068 #include "prprf.h"
00069 #include "rdf.h"
00070 
00071 #include "nsICharsetConverterManager.h"
00072 #include "nsICharsetAlias.h"
00073 
00074 static NS_DEFINE_CID(kRDFServiceCID,              NS_RDFSERVICE_CID);
00075 static NS_DEFINE_CID(kRDFInMemoryDataSourceCID,   NS_RDFINMEMORYDATASOURCE_CID);
00076 static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID);
00077 static NS_DEFINE_CID(kPrefCID,                    NS_PREF_CID);
00078 
00079 static const char kURINC_RelatedLinksRoot[] = "NC:RelatedLinks";
00080 
00081 nsString              *RelatedLinksHandlerImpl::mRLServerURL = nsnull;
00082 PRInt32               RelatedLinksHandlerImpl::gRefCnt = 0;
00083 nsIRDFService    *RelatedLinksHandlerImpl::gRDFService;
00084 nsIRDFResource        *RelatedLinksHandlerImpl::kNC_RelatedLinksRoot;
00085 nsIRDFResource        *RelatedLinksHandlerImpl::kNC_Child;
00086 nsIRDFResource        *RelatedLinksHandlerImpl::kRDF_type;
00087 nsIRDFResource        *RelatedLinksHandlerImpl::kNC_RelatedLinksTopic;
00088 
00089 
00091 // RelatedLinksStreamListener
00092 //
00093 //   Until Netcenter produces valid RDF/XML, we'll use this kludge to
00094 //   parse the crap they send us.
00095 //
00096 
00097 class RelatedLinksStreamListener : public nsIStreamListener
00098 {
00099 private:
00100        nsCOMPtr<nsIRDFDataSource>  mDataSource;
00101        nsVoidArray                 mParentArray;
00102 
00103        // pseudo-constants
00104        static PRInt32                     gRefCnt;
00105        static nsIRDFService        *gRDFService;
00106        static nsIRDFResource              *kNC_Child;
00107        static nsIRDFResource              *kNC_Name;
00108        static nsIRDFResource              *kNC_URL;
00109        static nsIRDFResource              *kNC_loading;
00110        static nsIRDFResource              *kNC_RelatedLinksRoot;
00111        static nsIRDFResource              *kNC_BookmarkSeparator;
00112        static nsIRDFResource              *kNC_RelatedLinksTopic;
00113        static nsIRDFResource              *kRDF_type;
00114        static nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder;
00115 
00116        nsAutoString                mBuffer;
00117 
00118 public:
00119 
00120         NS_DECL_ISUPPORTS
00121 
00122                      RelatedLinksStreamListener(nsIRDFDataSource *ds);
00123         virtual      ~RelatedLinksStreamListener();
00124 
00125         NS_METHOD    Init();
00126      nsresult   Unescape(nsString &text);
00127 
00128        // nsIRequestObserver
00129        NS_DECL_NSIREQUESTOBSERVER
00130 
00131        // nsIStreamListener
00132        NS_DECL_NSISTREAMLISTENER
00133 };
00134 
00135 
00136 
00137 PRInt32                     RelatedLinksStreamListener::gRefCnt;
00138 nsIRDFService        *RelatedLinksStreamListener::gRDFService;
00139 
00140 nsIRDFResource              *RelatedLinksStreamListener::kNC_Child;
00141 nsIRDFResource              *RelatedLinksStreamListener::kNC_Name;
00142 nsIRDFResource              *RelatedLinksStreamListener::kNC_URL;
00143 nsIRDFResource              *RelatedLinksStreamListener::kNC_loading;
00144 nsIRDFResource              *RelatedLinksStreamListener::kNC_RelatedLinksRoot;
00145 nsIRDFResource              *RelatedLinksStreamListener::kNC_BookmarkSeparator;
00146 nsIRDFResource              *RelatedLinksStreamListener::kNC_RelatedLinksTopic;
00147 nsIRDFResource              *RelatedLinksStreamListener::kRDF_type;
00148 nsCOMPtr<nsIUnicodeDecoder> RelatedLinksStreamListener::mUnicodeDecoder;
00149 
00150 
00152 
00153 
00154 
00155 nsresult
00156 NS_NewRelatedLinksStreamListener(nsIRDFDataSource* aDataSource,
00157                              nsIStreamListener** aResult)
00158 {
00159         RelatedLinksStreamListener* result =
00160                new RelatedLinksStreamListener(aDataSource);
00161 
00162         if (! result)
00163                return NS_ERROR_OUT_OF_MEMORY;
00164 
00165         nsresult rv = result->Init();
00166         if (NS_FAILED(rv)) {
00167                delete result;
00168                return rv;
00169         }
00170 
00171         NS_ADDREF(result);
00172         *aResult = result;
00173         return NS_OK;
00174 }
00175 
00176 
00177 
00178 RelatedLinksStreamListener::RelatedLinksStreamListener(nsIRDFDataSource *aDataSource)
00179         : mDataSource(aDataSource)
00180 {
00181 }
00182 
00183 
00184 
00185 RelatedLinksStreamListener::~RelatedLinksStreamListener()
00186 {
00187         if (--gRefCnt == 0)
00188         {
00189                NS_IF_RELEASE(kNC_Child);
00190                NS_IF_RELEASE(kNC_Name);
00191                NS_IF_RELEASE(kNC_URL);
00192                NS_IF_RELEASE(kNC_loading);
00193                NS_IF_RELEASE(kNC_BookmarkSeparator);
00194                NS_IF_RELEASE(kNC_RelatedLinksTopic);
00195                NS_IF_RELEASE(kRDF_type);
00196                NS_IF_RELEASE(kNC_RelatedLinksRoot);
00197                mUnicodeDecoder = nsnull;
00198 
00199                NS_IF_RELEASE(gRDFService);
00200         }
00201 }
00202 
00203 
00204 
00205 NS_METHOD
00206 RelatedLinksStreamListener::Init()
00207 {
00208        if (gRefCnt++ == 0)
00209        {
00210               nsresult rv = CallGetService(kRDFServiceCID, &gRDFService);
00211               if (NS_FAILED(rv))
00212     {
00213       NS_ERROR("unable to get RDF service");
00214                      return(rv);
00215     }
00216 
00217               nsICharsetConverterManager *charsetConv;
00218               rv = CallGetService(kCharsetConverterManagerCID, &charsetConv);
00219               if (NS_SUCCEEDED(rv))
00220               {
00221                      rv = charsetConv->GetUnicodeDecoderRaw("UTF-8",
00222                                                                                     getter_AddRefs(mUnicodeDecoder));
00223                      NS_RELEASE(charsetConv);
00224               }
00225 
00226               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"),
00227                              &kNC_Child);
00228               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "Name"),
00229                              &kNC_Name);
00230               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "URL"),
00231                              &kNC_URL);
00232               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "loading"),
00233                              &kNC_loading);
00234               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "BookmarkSeparator"),
00235                              &kNC_BookmarkSeparator);
00236               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "RelatedLinksTopic"),
00237                              &kNC_RelatedLinksTopic);
00238               gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"),
00239                              &kRDF_type);
00240               gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_RelatedLinksRoot),
00241                              &kNC_RelatedLinksRoot);
00242         }
00243 
00244         mParentArray.AppendElement(kNC_RelatedLinksRoot);
00245         return(NS_OK);
00246 }
00247 
00248 
00249 
00250 // nsISupports interface
00251 NS_IMPL_ISUPPORTS1(RelatedLinksStreamListener, nsIStreamListener)
00252 
00253 
00254 
00255 // stream observer methods
00256 
00257 
00258 
00259 NS_IMETHODIMP
00260 RelatedLinksStreamListener::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
00261 {
00262         nsIRDFLiteral              *literal = nsnull;
00263         nsresult            rv;
00264         if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(NS_LITERAL_STRING("true").get(), &literal)))
00265         {
00266                mDataSource->Assert(kNC_RelatedLinksRoot, kNC_loading, literal, PR_TRUE);
00267                NS_RELEASE(literal);
00268         }
00269         return(NS_OK);
00270 }
00271 
00272 
00273 
00274 NS_IMETHODIMP
00275 RelatedLinksStreamListener::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
00276                                           nsresult status)
00277 {
00278         nsIRDFLiteral              *literal = nsnull;
00279         nsresult            rv;
00280        if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(NS_LITERAL_STRING("true").get(), &literal)))
00281        {
00282               mDataSource->Unassert(kNC_RelatedLinksRoot, kNC_loading, literal);
00283               NS_RELEASE(literal);
00284        }
00285        return(NS_OK);
00286 }
00287 
00288 
00289 
00290 // stream listener methods
00291 
00292 
00293 
00294 NS_IMETHODIMP
00295 RelatedLinksStreamListener::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
00296               nsIInputStream *aIStream, PRUint32 sourceOffset, PRUint32 aLength)
00297 {
00298        nsresult      rv = NS_OK;
00299 
00300        if (aLength < 1)     return(rv);
00301 
00302        PRUint32      count;
00303        char          *buffer = new char[ aLength ];
00304        if (!buffer)  return(NS_ERROR_OUT_OF_MEMORY);
00305 
00306        if (NS_FAILED(rv = aIStream->Read(buffer, aLength, &count)) || count == 0)
00307        {
00308 #ifdef DEBUG
00309               printf("Related Links datasource read failure.\n");
00310 #endif
00311               delete []buffer;
00312               return(rv);
00313        }
00314        if (count != aLength)
00315        {
00316 #ifdef DEBUG
00317               printf("Related Links datasource read # of bytes failure.\n");
00318 #endif
00319               delete []buffer;
00320               return(NS_ERROR_UNEXPECTED);
00321        }
00322 
00323        if (mUnicodeDecoder)
00324        {
00325               char                 *aBuffer = buffer;
00326               PRInt32                     unicharBufLen = 0;
00327               mUnicodeDecoder->GetMaxLength(aBuffer, aLength, &unicharBufLen);
00328               PRUnichar            *unichars = new PRUnichar [ unicharBufLen+1 ];
00329               do
00330               {
00331                      PRInt32              srcLength = aLength;
00332                      PRInt32              unicharLength = unicharBufLen;
00333                      rv = mUnicodeDecoder->Convert(aBuffer, &srcLength, unichars, &unicharLength);
00334                      unichars[unicharLength]=0;  //add this since the unicode converters can't be trusted to do so.
00335 
00336                      // Move the nsParser.cpp 00 -> space hack to here so it won't break UCS2 file
00337 
00338                      // Hack Start
00339                      for(PRInt32 i=0;i<unicharLength;i++)
00340                             if(0x0000 == unichars[i])   unichars[i] = 0x0020;
00341                      // Hack End
00342 
00343                      mBuffer.Append(unichars, unicharLength);
00344                      // if we failed, we consume one byte by replace it with U+FFFD
00345                      // and try conversion again.
00346                      if(NS_FAILED(rv))
00347                      {
00348                             mUnicodeDecoder->Reset();
00349                             mBuffer.Append( (PRUnichar)0xFFFD);
00350                             if(((PRUint32) (srcLength + 1)) > aLength)
00351                                    srcLength = aLength;
00352                             else 
00353                                    srcLength++;
00354                             aBuffer += srcLength;
00355                             aLength -= srcLength;
00356                      }
00357               } while (NS_FAILED(rv) && (aLength > 0));
00358               delete [] unichars;
00359               unichars = nsnull;
00360        }
00361        else
00362        {
00363               mBuffer.AppendWithConversion(buffer, aLength);
00364        }
00365        delete [] buffer;
00366        buffer = nsnull;
00367 
00368        // parse out any available lines
00369        while (PR_TRUE)
00370        {
00371               PRInt32 eol = mBuffer.FindCharInSet("\r\n");
00372               if (eol < 0)
00373               {
00374                      break;
00375               }
00376 
00377               nsAutoString  oneLiner;
00378               if (eol >= 0)
00379               {
00380                      mBuffer.Left(oneLiner, eol);
00381                      mBuffer.Cut(0, eol+1);
00382               }
00383               if (oneLiner.IsEmpty())     break;
00384 
00385 #if 0
00386               printf("RL: '%s'\n", NS_LossyConvertUCS2toASCII(oneLiner).get());
00387 #endif
00388 
00389               // yes, very primitive RDF parsing follows
00390 
00391               nsAutoString  child, title;
00392 
00393               child.Truncate();
00394               title.Truncate();
00395 
00396               // get href
00397               PRInt32 theStart = oneLiner.Find("<child href=\"", PR_TRUE);
00398               if (theStart == 0)
00399               {
00400                      // get child href
00401                      theStart += PL_strlen("<child href=\"");
00402                      oneLiner.Cut(0, theStart);
00403                      PRInt32 theEnd = oneLiner.FindChar('"');
00404                      if (theEnd > 0)
00405                      {
00406                             oneLiner.Mid(child, 0, theEnd);
00407                      }
00408                      // get child name
00409                      theStart = oneLiner.Find("name=\"", PR_TRUE);
00410                      if (theStart >= 0)
00411                      {
00412                             theStart += PL_strlen("name=\"");
00413                             oneLiner.Cut(0, theStart);
00414                             theEnd = oneLiner.FindChar('"');
00415                             if (theEnd > 0)
00416                             {
00417                                    oneLiner.Mid(title, 0, theEnd);
00418                             }
00419                      }
00420               }
00421               // check for separator
00422               else if ((theStart = oneLiner.Find("<child instanceOf=\"Separator1\"/>", PR_TRUE)) == 0)
00423               {
00424                      nsCOMPtr<nsIRDFResource>    newSeparator;
00425                      if (NS_SUCCEEDED(rv = gRDFService->GetAnonymousResource(getter_AddRefs(newSeparator))))
00426                      {
00427                             mDataSource->Assert(newSeparator, kRDF_type, kNC_BookmarkSeparator, PR_TRUE);
00428 
00429                             nsIRDFResource       *parent = kNC_RelatedLinksRoot;
00430                             PRInt32              numParents = mParentArray.Count();
00431                             if (numParents > 0)
00432                             {
00433                                    parent = (nsIRDFResource *)(mParentArray.ElementAt(numParents - 1));
00434                             }
00435                             mDataSource->Assert(parent, kNC_Child, newSeparator, PR_TRUE);
00436                      }
00437               }
00438               else
00439               {
00440                      theStart = oneLiner.Find("<Topic name=\"", PR_TRUE);
00441                      if (theStart == 0)
00442                      {
00443                             // get topic name
00444                             theStart += PL_strlen("<Topic name=\"");
00445                             oneLiner.Cut(0, theStart);
00446                             PRInt32 theEnd = oneLiner.FindChar('"');
00447                             if (theEnd > 0)
00448                             {
00449                                    oneLiner.Mid(title, 0, theEnd);
00450                             }
00451 
00452                             nsCOMPtr<nsIRDFResource>    newTopic;
00453                             if (NS_SUCCEEDED(rv = gRDFService->GetAnonymousResource(getter_AddRefs(newTopic))))
00454                             {
00455                                    mDataSource->Assert(newTopic, kRDF_type, kNC_RelatedLinksTopic, PR_TRUE);
00456                                    if (!title.IsEmpty())
00457                                    {
00458                         Unescape(title);
00459 
00460                                           const PRUnichar             *titleName = title.get();
00461                                           if (nsnull != titleName)
00462                                           {
00463                                                  nsCOMPtr<nsIRDFLiteral> nameLiteral;
00464                                                  if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(titleName, getter_AddRefs(nameLiteral))))
00465                                                  {
00466                                                         mDataSource->Assert(newTopic, kNC_Name, nameLiteral, PR_TRUE);
00467                                                  }
00468                                           }
00469                                    }
00470                                    mParentArray.AppendElement(newTopic);
00471                             }
00472 
00473                      }
00474                      else
00475                      {
00476                             theStart = oneLiner.Find("</Topic>", PR_TRUE);
00477                             if (theStart == 0)
00478                             {
00479                                    PRInt32              numParents = mParentArray.Count();
00480                                    if (numParents > 0)
00481                                    {
00482                                           nsIRDFResource       *aChild = (nsIRDFResource *)(mParentArray.ElementAt(numParents - 1));
00483                                           mParentArray.RemoveElementAt(numParents - 1);
00484                                           nsIRDFResource       *aParent = kNC_RelatedLinksRoot;
00485                                           if (numParents > 1)
00486                                           {
00487                                                  aParent = (nsIRDFResource *)(mParentArray.ElementAt(numParents - 2));
00488                                           }
00489                                           mDataSource->Assert(aParent, kNC_Child, aChild, PR_TRUE);
00490                                    }
00491                             }
00492                      }
00493               }
00494 
00495               if (!child.IsEmpty())
00496               {
00497 
00498 #if 0
00499                      printf("RL: '%s'  -  '%s'\n", NS_LossyConvertUCS2toASCII(title).get(), NS_LossyConvertUCS2toASCII(child).get());
00500 #endif
00501                      const PRUnichar      *url = child.get();
00502                      if (nsnull != url)
00503                      {
00504                             nsCOMPtr<nsIRDFResource>    relatedLinksChild;
00505                             rv = gRDFService->GetAnonymousResource(getter_AddRefs(relatedLinksChild));
00506                             if (NS_SUCCEEDED(rv))
00507                             {
00508                                    title.Trim(" ");
00509                                    if (!title.IsEmpty())
00510                                    {
00511                         Unescape(title);
00512 
00513                                           const PRUnichar      *name = title.get();
00514                                           if (nsnull != name)
00515                                           {
00516                                                  nsCOMPtr<nsIRDFLiteral>     nameLiteral;
00517                                                  if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(name, getter_AddRefs(nameLiteral))))
00518                                                  {
00519                                                         mDataSource->Assert(relatedLinksChild, kNC_Name, nameLiteral, PR_TRUE);
00520                                                  }
00521                                           }
00522                                    }
00523 
00524                                    // all related links are anonymous, so save off the "#URL" attribute
00525                                    nsCOMPtr<nsIRDFLiteral>     urlLiteral;
00526                                    if (NS_SUCCEEDED(rv = gRDFService->GetLiteral(url, getter_AddRefs(urlLiteral))))
00527                                    {
00528                                           mDataSource->Assert(relatedLinksChild, kNC_URL, urlLiteral, PR_TRUE);
00529                                    }
00530 
00531                                    nsIRDFResource       *parent;
00532                                    PRInt32       numParents = mParentArray.Count();
00533                                    if (numParents > 0)
00534                                    {
00535                                           parent = (nsIRDFResource *)(mParentArray.ElementAt(numParents - 1));
00536                                    }
00537                                    else
00538                                    {
00539                                           parent = kNC_RelatedLinksRoot;
00540                                    }
00541                                    mDataSource->Assert(parent, kNC_Child, relatedLinksChild, PR_TRUE);
00542                             }
00543                      }
00544               }
00545        }
00546        return(rv);
00547 }
00548 
00549 
00550 
00551 nsresult
00552 RelatedLinksStreamListener::Unescape(nsString &text)
00553 {
00554        // convert some HTML-escaped (such as "&lt;") values back
00555 
00556        PRInt32              offset=0;
00557 
00558        while((offset = text.FindChar((PRUnichar('&')), offset)) >= 0)
00559        {
00560               if (Substring(text, offset, 4).LowerCaseEqualsLiteral("&lt;"))
00561               {
00562                      text.Cut(offset, 4);
00563                      text.Insert(PRUnichar('<'), offset);
00564               }
00565               else if (Substring(text, offset, 4).LowerCaseEqualsLiteral("&gt;"))
00566               {
00567                      text.Cut(offset, 4);
00568                      text.Insert(PRUnichar('>'), offset);
00569               }
00570               else if (Substring(text, offset, 5).LowerCaseEqualsLiteral("&amp;"))
00571               {
00572                      text.Cut(offset, 5);
00573                      text.Insert(PRUnichar('&'), offset);
00574               }
00575               else if (Substring(text, offset, 6).LowerCaseEqualsLiteral("&quot;"))
00576               {
00577                      text.Cut(offset, 6);
00578                      text.Insert(PRUnichar('\"'), offset);
00579               }
00580 
00581               ++offset;
00582        }
00583        return(NS_OK);
00584 }
00585 
00586 RelatedLinksHandlerImpl::RelatedLinksHandlerImpl()
00587        : mRelatedLinksURL(nsnull)
00588 {
00589 }
00590 
00591 
00592 
00593 RelatedLinksHandlerImpl::~RelatedLinksHandlerImpl()
00594 {
00595        if (mRelatedLinksURL)
00596        {
00597               PL_strfree(mRelatedLinksURL);
00598               mRelatedLinksURL = nsnull;
00599        }
00600 
00601        if (--gRefCnt == 0)
00602        {
00603               delete mRLServerURL;
00604               mRLServerURL = nsnull;
00605 
00606               NS_IF_RELEASE(kNC_RelatedLinksRoot);
00607               NS_IF_RELEASE(kRDF_type);
00608               NS_IF_RELEASE(kNC_RelatedLinksTopic);
00609               NS_IF_RELEASE(kNC_Child);
00610 
00611               NS_IF_RELEASE(gRDFService);
00612        }
00613 }
00614 
00615 
00616 
00617 nsresult
00618 RelatedLinksHandlerImpl::Init()
00619 {
00620        nsresult      rv;
00621 
00622        if (gRefCnt++ == 0)
00623        {
00624               rv = CallGetService(kRDFServiceCID, &gRDFService);
00625               if (NS_FAILED(rv)) return rv;
00626 
00627               gRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_RelatedLinksRoot),
00628                              &kNC_RelatedLinksRoot);
00629               gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"),
00630                              &kRDF_type);
00631               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "RelatedLinksTopic"),
00632                              &kNC_RelatedLinksTopic);
00633               gRDFService->GetResource(NS_LITERAL_CSTRING(NC_NAMESPACE_URI "child"),
00634                              &kNC_Child);
00635 
00636               nsCOMPtr<nsIPref> prefServ(do_GetService(kPrefCID, &rv));
00637               mRLServerURL = new nsString();
00638               if (NS_SUCCEEDED(rv) && (prefServ))
00639               {
00640                      char   *prefVal = nsnull;
00641                      if (NS_SUCCEEDED(rv = prefServ->CopyCharPref("browser.related.provider",
00642                             &prefVal)) && (prefVal))
00643                      {
00644                             mRLServerURL->AssignWithConversion(prefVal);
00645                             nsCRT::free(prefVal);
00646                             prefVal = nsnull;
00647                      }
00648                      else
00649                      {
00650                             // no preference, so fallback to a well-known URL
00651                             mRLServerURL->AssignLiteral("http://www-rl.netscape.com/wtgn?");
00652                      }
00653               }
00654        }
00655 
00656        mInner = do_CreateInstance(kRDFInMemoryDataSourceCID, &rv);
00657        return rv;
00658 }
00659 
00660 
00661 // nsISupports interface
00662 
00663 NS_IMPL_ISUPPORTS2(RelatedLinksHandlerImpl, nsIRelatedLinksHandler, nsIRDFDataSource)
00664 
00665 // nsIRelatedLinksHandler interface
00666 
00667 NS_IMETHODIMP
00668 RelatedLinksHandlerImpl::GetURL(char** aURL)
00669 {
00670        NS_PRECONDITION(aURL != nsnull, "null ptr");
00671        if (! aURL)
00672               return NS_ERROR_NULL_POINTER;
00673 
00674        if (mRelatedLinksURL)
00675        {
00676               *aURL = nsCRT::strdup(mRelatedLinksURL);
00677               return *aURL ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00678        }
00679        else
00680        {
00681               *aURL = nsnull;
00682               return NS_OK;
00683        }
00684 }
00685 
00686 
00687 
00688 NS_IMETHODIMP
00689 RelatedLinksHandlerImpl::SetURL(const char* aURL)
00690 {
00691        NS_PRECONDITION(aURL != nsnull, "null ptr");
00692        if (! aURL)
00693               return NS_ERROR_NULL_POINTER;
00694 
00695        nsresult rv;
00696 
00697        if (mRelatedLinksURL)
00698               PL_strfree(mRelatedLinksURL);
00699 
00700        mRelatedLinksURL = PL_strdup(aURL);
00701        if (! mRelatedLinksURL)
00702               return NS_ERROR_OUT_OF_MEMORY;
00703 
00704        // Flush the old links. This'll force notifications to propagate, too.
00705        nsCOMPtr<nsIRDFPurgeableDataSource> purgeable = do_QueryInterface(mInner);
00706        NS_ASSERTION(purgeable, "uh oh, this datasource isn't purgeable!");
00707        if (! purgeable)
00708               return NS_ERROR_UNEXPECTED;
00709 
00710        rv = purgeable->Sweep();
00711        if (NS_FAILED(rv)) return rv;
00712 
00713        nsAutoString  relatedLinksQueryURL(*mRLServerURL);
00714        relatedLinksQueryURL.AppendWithConversion(mRelatedLinksURL);
00715 
00716        nsCOMPtr<nsIURI> url;
00717        rv = NS_NewURI(getter_AddRefs(url), relatedLinksQueryURL);
00718 
00719        if (NS_FAILED(rv)) return rv;
00720 
00721        nsCOMPtr<nsIStreamListener> listener;
00722        rv = NS_NewRelatedLinksStreamListener(mInner, getter_AddRefs(listener));
00723        if (NS_FAILED(rv)) return rv;
00724 
00725        // XXX: Should there be a LoadGroup?
00726        rv = NS_OpenURI(listener, nsnull, url, nsnull);
00727        if (NS_FAILED(rv)) return rv;
00728 
00729        return NS_OK;
00730 }
00731 
00732 
00733 
00734 // nsIRDFDataSource interface
00735 
00736 
00737 NS_IMETHODIMP
00738 RelatedLinksHandlerImpl::GetURI(char **aURI)
00739 {
00740        NS_PRECONDITION(aURI != nsnull, "null ptr");
00741        if (! aURI)
00742               return NS_ERROR_NULL_POINTER;
00743 
00744        // XXX We could munge in the current URL that we're looking at I
00745        // suppose. Not critical because this datasource shouldn't be
00746        // registered with the RDF service.
00747        *aURI = nsCRT::strdup("rdf:related-links");
00748        if (! *aURI)
00749               return NS_ERROR_OUT_OF_MEMORY;
00750 
00751        return NS_OK;
00752 }
00753 
00754 
00755 
00756 NS_IMETHODIMP
00757 RelatedLinksHandlerImpl::GetSource(nsIRDFResource* aProperty,
00758                                nsIRDFNode* aTarget,
00759                                PRBool aTruthValue,
00760                                nsIRDFResource** aSource)
00761 {
00762               return mInner->GetSource(aProperty, aTarget, aTruthValue, aSource);
00763 }
00764 
00765 
00766 
00767 NS_IMETHODIMP
00768 RelatedLinksHandlerImpl::GetSources(nsIRDFResource *aProperty,
00769                                 nsIRDFNode *aTarget,
00770                                 PRBool aTruthValue,
00771                                 nsISimpleEnumerator **aSources)
00772 {
00773               return mInner->GetSources(aProperty, aTarget, aTruthValue, aSources);
00774 }
00775 
00776 
00777 
00778 NS_IMETHODIMP
00779 RelatedLinksHandlerImpl::GetTarget(nsIRDFResource *aSource,
00780                                nsIRDFResource *aProperty,
00781                                PRBool aTruthValue,
00782                                nsIRDFNode **aTarget)
00783 {
00784        return mInner->GetTarget(aSource, aProperty, aTruthValue, aTarget);
00785 }
00786 
00787 
00788 
00789 NS_IMETHODIMP
00790 RelatedLinksHandlerImpl::GetTargets(nsIRDFResource* aSource,
00791                                 nsIRDFResource* aProperty,
00792                                 PRBool aTruthValue,
00793                                 nsISimpleEnumerator** aTargets)
00794 {
00795        return mInner->GetTargets(aSource, aProperty, aTruthValue, aTargets);
00796 }
00797 
00798 
00799 
00800 NS_IMETHODIMP
00801 RelatedLinksHandlerImpl::Assert(nsIRDFResource *aSource,
00802                             nsIRDFResource *aProperty,
00803                             nsIRDFNode *aTarget,
00804                             PRBool aTruthValue)
00805 {
00806        return NS_RDF_ASSERTION_REJECTED;
00807 }
00808 
00809 
00810 
00811 NS_IMETHODIMP
00812 RelatedLinksHandlerImpl::Unassert(nsIRDFResource *aSource,
00813                               nsIRDFResource *aProperty,
00814                               nsIRDFNode *aTarget)
00815 {
00816        return NS_RDF_ASSERTION_REJECTED;
00817 }
00818 
00819 
00820 
00821 NS_IMETHODIMP
00822 RelatedLinksHandlerImpl::Change(nsIRDFResource* aSource,
00823                                                         nsIRDFResource* aProperty,
00824                                                         nsIRDFNode* aOldTarget,
00825                                                         nsIRDFNode* aNewTarget)
00826 {
00827        return NS_RDF_ASSERTION_REJECTED;
00828 }
00829 
00830 
00831 
00832 NS_IMETHODIMP
00833 RelatedLinksHandlerImpl::Move(nsIRDFResource* aOldSource,
00834                                                    nsIRDFResource* aNewSource,
00835                                                    nsIRDFResource* aProperty,
00836                                                    nsIRDFNode* aTarget)
00837 {
00838        return NS_RDF_ASSERTION_REJECTED;
00839 }
00840 
00841 
00842 
00843 NS_IMETHODIMP
00844 RelatedLinksHandlerImpl::HasAssertion(nsIRDFResource *aSource,
00845                                   nsIRDFResource *aProperty,
00846                                   nsIRDFNode *aTarget,
00847                                   PRBool aTruthValue,
00848                                   PRBool *aResult)
00849 {
00850        return mInner->HasAssertion(aSource, aProperty, aTarget, aTruthValue, aResult);
00851 }
00852 
00853 NS_IMETHODIMP 
00854 RelatedLinksHandlerImpl::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, PRBool *result)
00855 {
00856        return mInner->HasArcIn(aNode, aArc, result);
00857 }
00858 
00859 NS_IMETHODIMP 
00860 RelatedLinksHandlerImpl::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, PRBool *result)
00861 {
00862        nsresult      rv;
00863 
00864        PRBool hasValueFlag = PR_FALSE;
00865        if (aArc == kNC_Child &&
00866               (aSource == kNC_RelatedLinksRoot) || 
00867               (NS_SUCCEEDED(rv = mInner->HasAssertion(aSource, kRDF_type,
00868                                                                                     kNC_RelatedLinksTopic, PR_TRUE,
00869                                                                                     &hasValueFlag))) &&
00870               (hasValueFlag == PR_TRUE))
00871        {
00872               *result = PR_TRUE;
00873        }
00874        else {
00875               *result = PR_FALSE;
00876        }
00877        return NS_OK;
00878 }
00879 
00880 NS_IMETHODIMP
00881 RelatedLinksHandlerImpl::ArcLabelsIn(nsIRDFNode *aTarget,
00882                                  nsISimpleEnumerator **aLabels)
00883 {
00884        return mInner->ArcLabelsIn(aTarget, aLabels);
00885 }
00886 
00887 
00888 
00889 NS_IMETHODIMP
00890 RelatedLinksHandlerImpl::ArcLabelsOut(nsIRDFResource *aSource,
00891                                   nsISimpleEnumerator **aLabels)
00892 {
00893        nsresult      rv;
00894 
00895        nsCOMPtr<nsISupportsArray> array;
00896        rv = NS_NewISupportsArray(getter_AddRefs(array));
00897        if (NS_FAILED(rv)) return rv;
00898 
00899        nsISimpleEnumerator* result = new nsArrayEnumerator(array);
00900        if (! result) return(NS_ERROR_OUT_OF_MEMORY);
00901 
00902        PRBool hasValueFlag = PR_FALSE;
00903        if ((aSource == kNC_RelatedLinksRoot) || 
00904               (NS_SUCCEEDED(rv = mInner->HasAssertion(aSource, kRDF_type,
00905               kNC_RelatedLinksTopic, PR_TRUE, &hasValueFlag))) &&
00906               (hasValueFlag == PR_TRUE))
00907        {
00908               array->AppendElement(kNC_Child);
00909        }
00910        NS_ADDREF(result);
00911        *aLabels = result;
00912        return(NS_OK);
00913 }
00914 
00915 
00916 
00917 NS_IMETHODIMP
00918 RelatedLinksHandlerImpl::GetAllResources(nsISimpleEnumerator** aCursor)
00919 {
00920        return mInner->GetAllResources(aCursor);
00921 }
00922 
00923 
00924 
00925 NS_IMETHODIMP
00926 RelatedLinksHandlerImpl::AddObserver(nsIRDFObserver *aObserver)
00927 {
00928        return mInner->AddObserver(aObserver);
00929 }
00930 
00931 
00932 
00933 NS_IMETHODIMP
00934 RelatedLinksHandlerImpl::RemoveObserver(nsIRDFObserver *aObserver)
00935 {
00936        return mInner->RemoveObserver(aObserver);
00937 }
00938 
00939 
00940 
00941 NS_IMETHODIMP
00942 RelatedLinksHandlerImpl::GetAllCmds(nsIRDFResource* aSource,
00943                                    nsISimpleEnumerator/*<nsIRDFResource>*/** aCommands)
00944 {
00945        return mInner->GetAllCmds(aSource, aCommands);
00946 }
00947 
00948 
00949 
00950 NS_IMETHODIMP
00951 RelatedLinksHandlerImpl::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
00952                             nsIRDFResource*   aCommand,
00953                             nsISupportsArray/*<nsIRDFResource>*/* aArguments,
00954                                PRBool* aResult)
00955 {
00956        return mInner->IsCommandEnabled(aSources, aCommand, aArguments, aResult);
00957 }
00958 
00959 
00960 
00961 NS_IMETHODIMP
00962 RelatedLinksHandlerImpl::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
00963                             nsIRDFResource*   aCommand,
00964                             nsISupportsArray/*<nsIRDFResource>*/* aArguments)
00965 {
00966        return mInner->DoCommand(aSources, aCommand, aArguments);
00967 }
00968 
00969 
00970 
00971 NS_IMETHODIMP
00972 RelatedLinksHandlerImpl::BeginUpdateBatch()
00973 {
00974         return mInner->BeginUpdateBatch();
00975 }
00976 
00977 
00978 
00979 NS_IMETHODIMP
00980 RelatedLinksHandlerImpl::EndUpdateBatch()
00981 {
00982         return mInner->EndUpdateBatch();
00983 }