зеркало из https://github.com/mozilla/pjs.git
Bug 318057 r=ben bookmarks.html exporter, modifications to importer
This commit is contained in:
Родитель
0a9719a82d
Коммит
26583ebdfd
|
@ -243,6 +243,22 @@ var PlacesOrganizer = {
|
|||
var features = "modal,centerscreen,chrome,resizable=no";
|
||||
openDialog("chrome://browser/content/migration/migration.xul",
|
||||
"", features, "bookmarks");
|
||||
},
|
||||
|
||||
/**
|
||||
* Allows simple exporting of bookmarks.
|
||||
*/
|
||||
exportBookmarks: function PO_export() {
|
||||
var fp = Cc["@mozilla.org/filepicker;1"].
|
||||
createInstance(Ci.nsIFilePicker);
|
||||
fp.init(window, "", Ci.nsIFilePicker.modeSave);
|
||||
fp.appendFilters(Ci.nsIFilePicker.filterHTML);
|
||||
fp.defaultString = "bookmarks.html";
|
||||
if (fp.show() != Ci.nsIFilePicker.returnCancel) {
|
||||
var bms = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
bms.exportBookmarksHTML(fp.file);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@
|
|||
oncommand="PlacesSearchBox.findCurrent();"/>
|
||||
<command id="placesCmd_export"
|
||||
label="&cmd.export.label;" accesskey="&cmd.export.accesskey;"
|
||||
disabled="true"/>
|
||||
oncommand="PlacesOrganizer.exportBookmarks();"/>
|
||||
<command id="placesCmd_import"
|
||||
label="&cmd.import.label;" accesskey="&cmd.import.accesskey;"
|
||||
oncommand="PlacesOrganizer.importBookmarks();"/>
|
||||
|
|
|
@ -1,506 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Places.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian Ryner <bryner@brianryner.com> (original author)
|
||||
* Joe Hughes <joe@retrovirus.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
%{C++
|
||||
#include "nsTArray.h"
|
||||
#include "prtypes.h"
|
||||
%}
|
||||
|
||||
interface nsIURI;
|
||||
interface nsITransaction;
|
||||
|
||||
[ptr] native PRInt64Array(nsTArray<PRInt64>);
|
||||
|
||||
/**
|
||||
* Observer for bookmark changes.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(b13edc57-b427-4abc-b1e3-dea577489596)]
|
||||
interface nsINavBookmarkObserver : nsISupports
|
||||
{
|
||||
/**
|
||||
* Notify this observer that a batch transaction has started.
|
||||
* Other notifications will be sent during the batch change,
|
||||
* but the observer is guaranteed that onEndUpdateBatch() will be called
|
||||
* at the completion of changes.
|
||||
*/
|
||||
void onBeginUpdateBatch();
|
||||
|
||||
/**
|
||||
* Notify this observer that a batch transaction has ended.
|
||||
*/
|
||||
void onEndUpdateBatch();
|
||||
|
||||
/**
|
||||
* Notify this observer that the bookmark was added. Called after the actual
|
||||
* add took place. The rest of the bookmarks will be shifted down, but no
|
||||
* additional notifications will be sent.
|
||||
*
|
||||
* @param bookmark The bookmark item that was added.
|
||||
* @param folder The folder that the item was added to.
|
||||
* @param index The item's index in the folder.
|
||||
*/
|
||||
void onItemAdded(in nsIURI bookmark, in PRInt64 folder, in PRInt32 index);
|
||||
|
||||
/**
|
||||
* Notify this observer that the bookmark was removed. Called after the
|
||||
* actual remove took place. The bookmarks following the index will be
|
||||
* shifted up, but no additional notifications will be sent.
|
||||
*
|
||||
* @param bookmark The bookmark item will be removed.
|
||||
* @param folder The folder that the item was removed from.
|
||||
* @param index The bookmark's index in the folder.
|
||||
*/
|
||||
void onItemRemoved(in nsIURI bookmark, in PRInt64 folder, in PRInt32 index);
|
||||
|
||||
/**
|
||||
* Notify this observer that a bookmark's information has changed. This
|
||||
* will be called whenever any attributes like "title" are changed.
|
||||
*
|
||||
* @param bookmark The bookmark which changed.
|
||||
* @param property The property which changed.
|
||||
*
|
||||
* property = "cleartime" (history was deleted, there is no last visit date):
|
||||
* value = none
|
||||
* property = "title": value = new title
|
||||
* property = "favicon": value = new "moz-anno" URL of favicon image
|
||||
*/
|
||||
void onItemChanged(in nsIURI bookmark, in ACString property,
|
||||
in AString value);
|
||||
|
||||
/**
|
||||
* Notify that the item was visited. Normally in bookmarks we use the last
|
||||
* visit date, and normally the time will be a new visit that will be more
|
||||
* recent, but this is not guaranteed. You should check to see if it's
|
||||
* actually more recent before using this new time.
|
||||
*
|
||||
* @see onItemChanged properth = "cleartime" for when all visit dates are
|
||||
* deleted for the URI.
|
||||
*/
|
||||
void onItemVisited(in nsIURI bookmark, in PRInt64 aVisitID, in PRTime time);
|
||||
|
||||
/**
|
||||
* Notify this observer that a bookmark has been replaced.
|
||||
*
|
||||
* @param folder The folder in which the bookmark was replaced
|
||||
* @param item The item which was replaced
|
||||
* @param newItem The new item which replaced item
|
||||
*/
|
||||
void onItemReplaced(in PRInt64 folder, in nsIURI item, in nsIURI newItem);
|
||||
|
||||
/**
|
||||
* Notify this observer that a bookmark folder has been added.
|
||||
* @param folder The id of the folder that was added.
|
||||
* @param parent The id of the folder's parent.
|
||||
* @param index The folder's index inside its parent.
|
||||
*/
|
||||
void onFolderAdded(in PRInt64 folder, in PRInt64 parent, in PRInt32 index);
|
||||
|
||||
/**
|
||||
* Notify this observer that a bookmark folder has been removed.
|
||||
* @param folder The id of the folder that was removed.
|
||||
* @param parent The id of the folder's old parent.
|
||||
* @param index The folder's old index in its parent.
|
||||
*/
|
||||
void onFolderRemoved(in PRInt64 folder, in PRInt64 parent, in PRInt32 index);
|
||||
|
||||
/**
|
||||
* Notify this observer that a bookmark folder has been moved.
|
||||
* @param folder The id of the folder that was moved.
|
||||
* @param oldParent The id of the folder's old parent.
|
||||
* @param oldIndex The folder's old index inside oldParent.
|
||||
* @param newParent The id of the folder's new parent.
|
||||
* @param newIndex The folder's index inside newParent.
|
||||
*/
|
||||
void onFolderMoved(in PRInt64 folder,
|
||||
in PRInt64 oldParent, in PRInt32 oldIndex,
|
||||
in PRInt64 newParent, in PRInt32 newIndex);
|
||||
|
||||
/**
|
||||
* Notify this observer that a bookmark folder's information has changed.
|
||||
* This will be called whenever any attributes like "title" are changed.
|
||||
* @param folder The id of the folder that was changed.
|
||||
* @param property The property that was changed.
|
||||
*/
|
||||
void onFolderChanged(in PRInt64 folder, in ACString property);
|
||||
|
||||
/**
|
||||
* Notify this observer that a separator has been added.
|
||||
* @param parent The id of the separator's parent.
|
||||
* @param index The separator's index inside its parent.
|
||||
*/
|
||||
void onSeparatorAdded(in PRInt64 parent, in PRInt32 index);
|
||||
|
||||
/**
|
||||
* Notify this observer that a separator has been removed.
|
||||
* @param parent The id of the separator's parent.
|
||||
* @param index The separator's old index in its parent.
|
||||
*/
|
||||
void onSeparatorRemoved(in PRInt64 parent, in PRInt32 index);
|
||||
};
|
||||
|
||||
/**
|
||||
* The BookmarksService interface provides methods for managing bookmarked
|
||||
* history items. Bookmarks consist of a set of user-customizable
|
||||
* folders. A URI in history can be contained in one or more such folders.
|
||||
*/
|
||||
|
||||
[scriptable, uuid(860d786d-9bba-4011-a396-486a87af8f07)]
|
||||
interface nsINavBookmarksService : nsISupports
|
||||
{
|
||||
/**
|
||||
* The folder ID of the Places root.
|
||||
*/
|
||||
readonly attribute PRInt64 placesRoot;
|
||||
|
||||
/**
|
||||
* The folder ID of the bookmarks root.
|
||||
*/
|
||||
readonly attribute PRInt64 bookmarksRoot;
|
||||
|
||||
/**
|
||||
* The folder ID of the personal toolbar root.
|
||||
*/
|
||||
readonly attribute PRInt64 toolbarRoot;
|
||||
|
||||
/**
|
||||
* The folder ID of the top-level folders that contain the tag "folders".
|
||||
*
|
||||
* NOTE: This isn't wired up yet, so don't try to use it for anything until
|
||||
* bug 329961 is marked resolved.
|
||||
*/
|
||||
readonly attribute PRInt64 tagRoot;
|
||||
|
||||
/**
|
||||
* Inserts a child item into the given folder. If this item already exists in
|
||||
* the given folder, it will be moved to the new position.
|
||||
* @param folder The id of the parent folder
|
||||
* @param item The URI to insert
|
||||
* @param index The index to insert at, or -1 to append
|
||||
*/
|
||||
void insertItem(in PRInt64 folder, in nsIURI item, in PRInt32 index);
|
||||
|
||||
/**
|
||||
* Removes a child item from the given folder.
|
||||
* @param folder The folder to remove the child from
|
||||
* @param item The child item to remove
|
||||
*/
|
||||
void removeItem(in PRInt64 folder, in nsIURI child);
|
||||
|
||||
/**
|
||||
* Replace an item with a different item.
|
||||
* @param folder The folder which contains the item to replace
|
||||
* @param item The item which should be replaced
|
||||
* @param newItem The new item
|
||||
*/
|
||||
void replaceItem(in PRInt64 folder, in nsIURI item, in nsIURI newItem);
|
||||
|
||||
/**
|
||||
* Creates a new child folder and inserts it under the given parent.
|
||||
* @param parent The id of the parent folder
|
||||
* @param name The name of the new folder
|
||||
* @param index The index to insert at, or -1 to append
|
||||
* @returns the ID of the newly-inserted folder
|
||||
*/
|
||||
PRInt64 createFolder(in PRInt64 parent, in AString name, in PRInt32 index);
|
||||
|
||||
/**
|
||||
* Wrapper for container services. Creates a folder under the given
|
||||
* parent and sets the container type.
|
||||
* @param parent The id of the parent folder
|
||||
* @param name The name of the new folder
|
||||
* @param type The type of container to insert
|
||||
* @param index The index to insert at, or -1 to append
|
||||
* @returns the ID of the newly-inserted folder
|
||||
*/
|
||||
PRInt64 createContainer(in PRInt64 parent, in AString name,
|
||||
in AString type, in PRInt32 index);
|
||||
|
||||
/**
|
||||
* Removes a folder from the bookmarks tree.
|
||||
* @param folder The id of the folder to remove.
|
||||
*/
|
||||
void removeFolder(in PRInt64 folder);
|
||||
|
||||
/**
|
||||
* Gets an undo-able transaction for removing a folder from the bookmarks
|
||||
* tree.
|
||||
* @param folder The id of the folder to remove.
|
||||
* @returns An object implementing nsITransaction that can be used to undo
|
||||
* or redo the action.
|
||||
*
|
||||
* This method exists because complex delete->undo operations rely on
|
||||
* recreated folders to have the same ID they had before they were deleted,
|
||||
* so that any other items deleted in different transactions can be
|
||||
* re-inserted correctly. This provides a safe encapsulation of this
|
||||
* functionality without exposing the ability to recreate folders with
|
||||
* specific IDs (potentially dangerous if abused by other code!) in the
|
||||
* public API.
|
||||
*/
|
||||
nsITransaction getRemoveFolderTransaction(in PRInt64 folder);
|
||||
|
||||
/**
|
||||
* Convenience function for container services. Removes
|
||||
* all children of the given folder.
|
||||
* @param folder The id of the folder to remove children from.
|
||||
*/
|
||||
void removeFolderChildren(in PRInt64 folder);
|
||||
|
||||
/**
|
||||
* Moves a folder to a different container, preserving its contents.
|
||||
* @param folder The folder to move
|
||||
* @param newParent The id of the folder's new parent
|
||||
* @param index The folder's index under newParent, or -1 to append
|
||||
*/
|
||||
void moveFolder(in PRInt64 folder, in PRInt64 newParent, in PRInt32 index);
|
||||
|
||||
/**
|
||||
* Returns the ID of a child folder with the given name. This does not
|
||||
* recurse, you have to give it an immediate sibling of the given folder.
|
||||
* If the given subfolder doesn't exist, it will return 0.
|
||||
* @param folder Parent folder whose children we will search
|
||||
* @param subFolder Name of the folder to search for in folder
|
||||
*/
|
||||
PRInt64 getChildFolder(in PRInt64 folder, in AString subFolder);
|
||||
|
||||
/**
|
||||
* Inserts a bookmark separator into the given folder at the given index.
|
||||
* The separator can be removed using removeChildAt().
|
||||
* @param folder Parent folder of the separator
|
||||
* @param index The separator's index under folder, or -1 to append
|
||||
*/
|
||||
void insertSeparator(in PRInt64 folder, in PRInt32 index);
|
||||
|
||||
/**
|
||||
* Removes any type of child (item, folder, or separator) at the given index.
|
||||
* @param folder The folder to remove a child from
|
||||
* @param index The index of the child to remove
|
||||
*/
|
||||
void removeChildAt(in PRInt64 folder, in PRInt32 index);
|
||||
|
||||
/**
|
||||
* Set the history/bookmark title for a URI. The new title will be used
|
||||
* anywhere the URI is shown in bookmarks or history.
|
||||
* @param uri The URI whose name should be set
|
||||
* @param title The new title for the URI
|
||||
*/
|
||||
void setItemTitle(in nsIURI uri, in AString title);
|
||||
|
||||
/**
|
||||
* Get the history/bookmark title for the URI.
|
||||
*
|
||||
* If no item title is available (for instance, if the URI doesn't appear
|
||||
* in the bookmarks or history), it will return a void string (null in JS).
|
||||
*
|
||||
* @param uri The URI whose title should be retrieved
|
||||
* @returns The title for the URI.
|
||||
*/
|
||||
AString getItemTitle(in nsIURI uri);
|
||||
|
||||
/**
|
||||
* Set the title for a bookmark folder.
|
||||
* @param folder The folder whose title should be set
|
||||
* @param title The new title for the folder
|
||||
*/
|
||||
void setFolderTitle(in PRInt64 folder, in AString title);
|
||||
|
||||
/**
|
||||
* Get the title for a bookmark folder. Throws an invalid argument
|
||||
* exception if it can't find a folder with the given ID.
|
||||
*
|
||||
* @param folder The folder whose title should be retrieved
|
||||
* @returns The title for the folder
|
||||
*/
|
||||
AString getFolderTitle(in PRInt64 folder);
|
||||
|
||||
/**
|
||||
* Get the place: url for a bookmark folder. You can use this value to
|
||||
* get/set the icon for a folder or to associate other data with it using
|
||||
* the annotation service. Its important that you use this function instead
|
||||
* of just serializing the query/options for a given folder because you
|
||||
* may have different options or query parameters. This function will give
|
||||
* the canonical value.
|
||||
* @param folder The folder whose URI should be retrieved
|
||||
* @returns The URI for the folder
|
||||
*/
|
||||
nsIURI getFolderURI(in PRInt64 folder);
|
||||
|
||||
/**
|
||||
* Checks whether a folder has read-only children. This property is
|
||||
* defined by the nsIBookmarsContainer for the folder, if one exists.
|
||||
* If this is set to true, UI should not allow the user to add, remove,
|
||||
* or reorder children in this folder. The default for all folders is false.
|
||||
*/
|
||||
boolean getFolderReadonly(in PRInt64 folder);
|
||||
|
||||
/**
|
||||
* Returns true if the given URI is in any bookmark folder. If you want the
|
||||
* results to be redirect-aware, use getBookmarkedURIFor()
|
||||
*/
|
||||
boolean isBookmarked(in nsIURI uri);
|
||||
|
||||
/**
|
||||
* Used to see if the given URI is bookmarked, or any page that redirected to
|
||||
* it is bookmarked. For example, if I bookmark "mozilla.org" by manually
|
||||
* typing it in, and follow the bookmark, I will get redirected to
|
||||
* "www.mozilla.org". Logically, this new page is also bookmarked. This
|
||||
* function, if given "www.mozilla.org", will return the URI of the bookmark,
|
||||
* in this case "mozilla.org".
|
||||
*
|
||||
* If there is no bookmarked page found, it will return NULL.
|
||||
*/
|
||||
nsIURI getBookmarkedURIFor(in nsIURI uri);
|
||||
|
||||
/**
|
||||
* "Changes" the URI of a bookmark. Since URIs are the unique
|
||||
* identifiers of bookmarks in this system, what this really means is
|
||||
* that all the metadata attached to oldURI will be copied onto newURI,
|
||||
* and oldURI will be deleted from the bookmark system. If newURI
|
||||
* is already bookmarked, the metadata from oldURI will overwrite
|
||||
* the corresponding metadata on newURI. Any annotations on oldURI
|
||||
* will be copied to newURI (a copy will remain on oldURI).
|
||||
*/
|
||||
|
||||
void changeBookmarkURI(in nsIURI oldURI, in nsIURI newURI);
|
||||
|
||||
/**
|
||||
* Returns the list of folder ids that contain the given URI.
|
||||
*/
|
||||
void getBookmarkFolders(in nsIURI uri, out PRUint32 count,
|
||||
[array, retval, size_is(count)] out PRInt64 folders);
|
||||
|
||||
/**
|
||||
* TArray version of getBookmarkFolders for ease of use in C++ code.
|
||||
* Pass in a reference to a TArray; it will get cleared and filled with
|
||||
* the resulting list of folder IDs.
|
||||
*/
|
||||
[noscript] void getBookmarkFoldersTArray(in nsIURI aURI,
|
||||
in PRInt64Array aResult);
|
||||
|
||||
/**
|
||||
* Returns the index of the given item in the given folder.
|
||||
* Returns -1 if the item is not present in the folder.
|
||||
*/
|
||||
PRInt32 indexOfItem(in PRInt64 folder, in nsIURI uri);
|
||||
|
||||
/**
|
||||
* Returns the index of the given subfolder in its parent.
|
||||
* Returns -1 if the subfolder is not present in the parent folder.
|
||||
*/
|
||||
PRInt32 indexOfFolder(in PRInt64 parent, in PRInt64 folder);
|
||||
|
||||
/**
|
||||
* Associates the given keyword with the given URI.
|
||||
*
|
||||
* Use an empty keyword to clear the keyword associated with the URI. Use an
|
||||
* empty URI to clear the URI associated with that keyword. In both of these
|
||||
* cases, succeeds but does nothing if the URL/keyword is not found.
|
||||
*
|
||||
* When setting a keyword (both URI and keyword are specified), the URI must
|
||||
* be bookmarked for the keyword to be persistent.
|
||||
*/
|
||||
void setKeywordForURI(in nsIURI uri, in AString keyword);
|
||||
|
||||
/**
|
||||
* Retrieves the keyword for the given URI. Will be void string
|
||||
* (null in JS) if no such keyword is found.
|
||||
*/
|
||||
AString getKeywordForURI(in nsIURI uri);
|
||||
|
||||
/**
|
||||
* Returns the URI associated with the given keyword. Empty if no such
|
||||
* keyword is found.
|
||||
*/
|
||||
nsIURI getURIForKeyword(in AString keyword);
|
||||
|
||||
/**
|
||||
* Adds a bookmark observer. If ownsWeak is false, the bookmark service will
|
||||
* keep an owning reference to the observer. If ownsWeak is true, then
|
||||
* aObserver must implement nsISupportsWeakReference, and the bookmark
|
||||
* service will keep a weak reference to the observer.
|
||||
*/
|
||||
void addObserver(in nsINavBookmarkObserver observer, in boolean ownsWeak);
|
||||
|
||||
/**
|
||||
* Removes a bookmark observer.
|
||||
*/
|
||||
void removeObserver(in nsINavBookmarkObserver observer);
|
||||
|
||||
/**
|
||||
* Causes observers to be notified of a beginUpdateBatch when a lot of things
|
||||
* are about to change. Calls can be nested, observers will only be
|
||||
* notified when all batches begin/end.
|
||||
*
|
||||
* It is EXTREMELY IMPORTANT that you call EndUpdateBatch for each call to
|
||||
* beginUpdateBatch. If you don't do this, certain parts of the UI will not
|
||||
* get updated and any changes to bookmarks will not get written to disk.
|
||||
* From C++ code inside the places component, use nsBookmarksUpdateBatcher
|
||||
* defined in nsNavBookmarks.h to scope batches. For JS or from other
|
||||
* components, just please be very careful to close the batch, especially
|
||||
* when encountering an error and returning early.
|
||||
*/
|
||||
void beginUpdateBatch();
|
||||
|
||||
/**
|
||||
* Causes observers to be notified of an endUpdateBatch when a batch is
|
||||
* done changing. Should match beginUpdateBatch or bad things will happen.
|
||||
*/
|
||||
void endUpdateBatch();
|
||||
|
||||
|
||||
/**
|
||||
* Loads the given bookmarks.html file and merges it with the current
|
||||
* bookmarks hierarchy.
|
||||
*/
|
||||
void importBookmarksHTML(in nsIURI url);
|
||||
|
||||
|
||||
/**
|
||||
* Loads the given bookmarks.html file and puts it in the given folder
|
||||
*/
|
||||
void importBookmarksHTMLToFolder(in nsIURI url, in PRInt64 folder);
|
||||
|
||||
|
||||
/**
|
||||
* Saves the current bookmarks hierarchy to a bookmarks.html file.
|
||||
*/
|
||||
void exportBookmarksHTML(in nsIURI url);
|
||||
};
|
|
@ -55,9 +55,11 @@
|
|||
* Bookmark := a
|
||||
* HREF is the destination of the bookmark
|
||||
* FEEDURL is the URI of the RSS feed if this is a livemark.
|
||||
* LAST_CHARSET should be stored as an annotation (FIXME TODO) so that the
|
||||
* LAST_CHARSET should be stored as an annotation (FIXME bug 334408) so that the
|
||||
* next time we go to that page we remember the user's preference.
|
||||
* ICON will be stored in the favicon service
|
||||
* ICON_URI is new for places bookmarks.html, it refers to the original
|
||||
* URI of the favicon so we don't have to make up favicon URLs.
|
||||
* Text of the <a> container is the name of the bookmark
|
||||
* Ignored: ADD_DATE, LAST_VISIT, LAST_MODIFIED, ID
|
||||
* Bookmark comment := dd
|
||||
|
@ -88,21 +90,26 @@
|
|||
|
||||
#include "nsBrowserCompsCID.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsFaviconService.h"
|
||||
#include "nsIAnnotationService.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIHTMLContentSink.h"
|
||||
#include "nsILivemarkService.h"
|
||||
#include "nsLivemarkService.h"
|
||||
#include "nsIParser.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsFaviconService.h"
|
||||
#include "nsNavBookmarks.h"
|
||||
#include "nsNavHistory.h"
|
||||
#include "nsNavHistoryResult.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsParserCIID.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "mozStorageHelper.h"
|
||||
#include "plbase64.h"
|
||||
#include "prtime.h"
|
||||
|
||||
static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
|
||||
|
||||
|
@ -113,11 +120,15 @@ static NS_DEFINE_CID(kParserCID, NS_PARSER_CID);
|
|||
#define KEY_FEEDURL_LOWER "feedurl"
|
||||
#define KEY_LASTCHARSET_LOWER "last_charset"
|
||||
#define KEY_ICON_LOWER "icon"
|
||||
#define KEY_ICON_URI_LOWER "icon_uri"
|
||||
#define KEY_SHORTCUTURL_LOWER "shortcuturl"
|
||||
|
||||
#define BOOKMARKS_MENU_ICON_URI "chrome://browser/skin/places/bookmarksMenu.png"
|
||||
#define BOOKMARKS_TOOLBAR_ICON_URI "chrome://browser/skin/places/bookmarksToolbar.png"
|
||||
|
||||
// define to get debugging messages on console about import
|
||||
//#define DEBUG_IMPORT
|
||||
|
||||
static const char kWhitespace[] = " \r\n\t\b";
|
||||
|
||||
class BookmarkImportFrame
|
||||
|
@ -132,6 +143,7 @@ public:
|
|||
}
|
||||
|
||||
enum ContainerType { Container_Normal,
|
||||
Container_Places,
|
||||
Container_Menu,
|
||||
Container_Toolbar };
|
||||
|
||||
|
@ -288,8 +300,18 @@ protected:
|
|||
nsresult NewFrame();
|
||||
nsresult PopFrame();
|
||||
|
||||
nsresult SetFaviconForURI(nsIURI* aURI, const nsCString& aData);
|
||||
nsresult SetFaviconForURI(nsIURI* aPageURI, nsIURI* aFaviconURI,
|
||||
const nsCString& aData);
|
||||
nsresult SetFaviconForFolder(PRInt64 aFolder, const nsACString& aFavicon);
|
||||
|
||||
#ifdef DEBUG_IMPORT
|
||||
// prints spaces for indenting to the current frame depth
|
||||
void PrintNesting()
|
||||
{
|
||||
for (PRUint32 i = 0; i < mFrames.Length(); i ++)
|
||||
printf(" ");
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
@ -349,8 +371,9 @@ BookmarkContentSink::OpenContainer(const nsIParserNode& aNode)
|
|||
if (frame.mInDescription) {
|
||||
frame.mPreviousText.Trim(kWhitespace); // important!
|
||||
if (! frame.mPreviousText.IsEmpty()) {
|
||||
// FIXME: This description should be stored as an annotation on the URL
|
||||
// or folder. We should probably not overwrite existing annotations.
|
||||
// FIXME bug 334758: This description should be stored as an annotation
|
||||
// on the URL or folder. We should probably not overwrite existing
|
||||
// annotations.
|
||||
frame.mPreviousText.Truncate(0);
|
||||
}
|
||||
frame.mInDescription = PR_FALSE;
|
||||
|
@ -552,6 +575,9 @@ BookmarkContentSink::HandleHeadBegin(const nsIParserNode& node)
|
|||
} else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_BOOKMARKSMENU_LOWER)) {
|
||||
frame.mLastContainerType = BookmarkImportFrame::Container_Menu;
|
||||
break;
|
||||
} else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_PLACESROOT_LOWER)) {
|
||||
frame.mLastContainerType = BookmarkImportFrame::Container_Places;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -593,6 +619,7 @@ BookmarkContentSink::HandleLinkBegin(const nsIParserNode& node)
|
|||
nsAutoString href;
|
||||
nsAutoString feedUrl;
|
||||
nsAutoString icon;
|
||||
nsAutoString iconUri;
|
||||
nsAutoString lastCharset;
|
||||
nsAutoString keyword;
|
||||
PRInt32 attrCount = node.GetAttributeCount();
|
||||
|
@ -604,6 +631,8 @@ BookmarkContentSink::HandleLinkBegin(const nsIParserNode& node)
|
|||
feedUrl = node.GetValueAt(i);
|
||||
} else if (key.LowerCaseEqualsLiteral(KEY_ICON_LOWER)) {
|
||||
icon = node.GetValueAt(i);
|
||||
} else if (key.LowerCaseEqualsLiteral(KEY_ICON_URI_LOWER)) {
|
||||
iconUri = node.GetValueAt(i);
|
||||
} else if (key.LowerCaseEqualsLiteral(KEY_LASTCHARSET_LOWER)) {
|
||||
lastCharset = node.GetValueAt(i);
|
||||
} else if (key.LowerCaseEqualsLiteral(KEY_SHORTCUTURL_LOWER)) {
|
||||
|
@ -613,6 +642,7 @@ BookmarkContentSink::HandleLinkBegin(const nsIParserNode& node)
|
|||
href.Trim(kWhitespace);
|
||||
feedUrl.Trim(kWhitespace);
|
||||
icon.Trim(kWhitespace);
|
||||
iconUri.Trim(kWhitespace);
|
||||
lastCharset.Trim(kWhitespace);
|
||||
keyword.Trim(kWhitespace);
|
||||
|
||||
|
@ -652,14 +682,19 @@ BookmarkContentSink::HandleLinkBegin(const nsIParserNode& node)
|
|||
mBookmarksService->InsertItem(frame.mContainerID, frame.mPreviousLink, -1);
|
||||
|
||||
// save the favicon, ignore errors
|
||||
if (! icon.IsEmpty())
|
||||
SetFaviconForURI(frame.mPreviousLink, NS_ConvertUTF16toUTF8(icon));
|
||||
if (! icon.IsEmpty() || ! iconUri.IsEmpty()) {
|
||||
nsCOMPtr<nsIURI> iconUriObject;
|
||||
NS_NewURI(getter_AddRefs(iconUriObject), iconUri);
|
||||
if (! icon.IsEmpty() || iconUriObject)
|
||||
SetFaviconForURI(frame.mPreviousLink, iconUriObject,
|
||||
NS_ConvertUTF16toUTF8(icon));
|
||||
}
|
||||
|
||||
// save the keyword, ignore errors
|
||||
if (! keyword.IsEmpty())
|
||||
mBookmarksService->SetKeywordForURI(frame.mPreviousLink, keyword);
|
||||
|
||||
// FIXME: save the last charset
|
||||
// FIXME bug 334408: save the last charset
|
||||
}
|
||||
|
||||
|
||||
|
@ -685,8 +720,18 @@ BookmarkContentSink::HandleLinkEnd()
|
|||
frame.mPreviousFeed,
|
||||
-1,
|
||||
&folderId);
|
||||
#ifdef DEBUG_IMPORT
|
||||
PrintNesting();
|
||||
printf("Creating livemark '%s'\n",
|
||||
NS_ConvertUTF16toUTF8(frame.mPreviousText).get());
|
||||
#endif
|
||||
}
|
||||
else if (frame.mPreviousLink) {
|
||||
#ifdef DEBUG_IMPORT
|
||||
PrintNesting();
|
||||
printf("Creating bookmark '%s'\n",
|
||||
NS_ConvertUTF16toUTF8(frame.mPreviousText).get());
|
||||
#endif
|
||||
mHistoryService->SetPageUserTitle(frame.mPreviousLink,
|
||||
frame.mPreviousText);
|
||||
}
|
||||
|
@ -707,6 +752,10 @@ BookmarkContentSink::HandleSeparator()
|
|||
// we want to skip over this separator since it looks out of place.
|
||||
if (frame.mLastContainerType != BookmarkImportFrame::Container_Toolbar) {
|
||||
// create the separator
|
||||
#ifdef DEBUG_IMPORT
|
||||
PrintNesting();
|
||||
printf("--------\n");
|
||||
#endif
|
||||
mBookmarksService->InsertSeparator(frame.mContainerID, -1);
|
||||
}
|
||||
}
|
||||
|
@ -741,6 +790,13 @@ BookmarkContentSink::NewFrame()
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
break;
|
||||
case BookmarkImportFrame::Container_Places:
|
||||
// places root
|
||||
rv = mBookmarksService->GetPlacesRoot(&ourID);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (mAllowRootChanges)
|
||||
updateFolder = PR_TRUE;
|
||||
break;
|
||||
case BookmarkImportFrame::Container_Menu:
|
||||
// menu root
|
||||
rv = mBookmarksService->GetBookmarksRoot(&ourID);
|
||||
|
@ -762,13 +818,24 @@ BookmarkContentSink::NewFrame()
|
|||
default:
|
||||
NS_NOTREACHED("Unknown container type");
|
||||
}
|
||||
#ifdef DEBUG_IMPORT
|
||||
PrintNesting();
|
||||
printf("Folder %lld \'%s\'", ourID, NS_ConvertUTF16toUTF8(containerName).get());
|
||||
#endif
|
||||
|
||||
if (updateFolder) {
|
||||
// move the menu/toolbar folder to the current position
|
||||
mBookmarksService->MoveFolder(ourID, CurFrame().mContainerID, -1);
|
||||
mBookmarksService->SetFolderTitle(ourID, containerName);
|
||||
#ifdef DEBUG_IMPORT
|
||||
printf(" [reparenting]");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_IMPORT
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
if (! mFrames.AppendElement(BookmarkImportFrame(ourID)))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
|
@ -794,15 +861,22 @@ BookmarkContentSink::PopFrame()
|
|||
// BookmarkContentSink::SetFaviconForURI
|
||||
//
|
||||
// aData is a string that is a data URI for the favicon. Our job is to
|
||||
// decode it and store it in the favicon service. We have to make up a URI
|
||||
// for this favicon so that it can be stored in the service. The real one
|
||||
// will be set the next time the user visits the page. Our made up one
|
||||
// should get expired when the page no longer references it.
|
||||
// decode it and store it in the favicon service.
|
||||
//
|
||||
// When aIconURI is non-null, we will use that as the URI of the favicon
|
||||
// when storing in the favicon service.
|
||||
//
|
||||
// When aIconURI is null, we have to make up a URI for this favicon so that
|
||||
// it can be stored in the service. The real one will be set the next time
|
||||
// the user visits the page. Our made up one should get expired when the
|
||||
// page no longer references it.
|
||||
|
||||
nsresult
|
||||
BookmarkContentSink::SetFaviconForURI(nsIURI* aURI, const nsCString& aData)
|
||||
BookmarkContentSink::SetFaviconForURI(nsIURI* aPageURI, nsIURI* aIconURI,
|
||||
const nsCString& aData)
|
||||
{
|
||||
nsresult rv;
|
||||
static PRUint32 serialNumber = 0; // for made-up favicon URIs
|
||||
|
||||
// some bookmarks have placeholder URIs that contain just "data:"
|
||||
// ignore these
|
||||
|
@ -813,17 +887,29 @@ BookmarkContentSink::SetFaviconForURI(nsIURI* aURI, const nsCString& aData)
|
|||
if (! faviconService)
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
|
||||
// make up favicon URL
|
||||
static PRUint32 serialNumber = 0;
|
||||
nsCAutoString faviconSpec;
|
||||
faviconSpec.AssignLiteral("http://www.mozilla.org/2005/made-up-favicon/");
|
||||
faviconSpec.AppendInt(serialNumber);
|
||||
faviconSpec.AppendLiteral("-");
|
||||
faviconSpec.AppendInt(PR_Now());
|
||||
// if the input favicon URI is a chrome: URI, then we just save it and don't
|
||||
// worry about data
|
||||
if (aIconURI) {
|
||||
nsCString faviconScheme;
|
||||
if (faviconScheme.EqualsLiteral("chrome")) {
|
||||
return faviconService->SetFaviconUrlForPage(aPageURI, aIconURI);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> faviconURI;
|
||||
rv = NS_NewURI(getter_AddRefs(faviconURI), faviconSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
serialNumber ++;
|
||||
if (aIconURI) {
|
||||
faviconURI = aIconURI;
|
||||
} else {
|
||||
// make up favicon URL
|
||||
nsCAutoString faviconSpec;
|
||||
faviconSpec.AssignLiteral("http://www.mozilla.org/2005/made-up-favicon/");
|
||||
faviconSpec.AppendInt(serialNumber);
|
||||
faviconSpec.AppendLiteral("-");
|
||||
faviconSpec.AppendInt(PR_Now());
|
||||
rv = NS_NewURI(getter_AddRefs(faviconURI), faviconSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
serialNumber ++;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> dataURI;
|
||||
rv = NS_NewURI(getter_AddRefs(dataURI), aData);
|
||||
|
@ -871,7 +957,7 @@ BookmarkContentSink::SetFaviconForURI(nsIURI* aURI, const nsCString& aData)
|
|||
rv = faviconService->SetFaviconData(faviconURI, buffer, available, mimeType, 0);
|
||||
nsMemory::Free(buffer);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return faviconService->SetFaviconUrlForPage(aURI, faviconURI);
|
||||
return faviconService->SetFaviconUrlForPage(aPageURI, faviconURI);
|
||||
}
|
||||
|
||||
|
||||
|
@ -949,6 +1035,12 @@ nsNavBookmarks::ImportBookmarksHTMLInternal(nsIURI* aURL,
|
|||
// wrap the import in a transaction to make it faster
|
||||
mozStorageTransaction transaction(DBConn(), PR_FALSE);
|
||||
|
||||
#ifdef DEBUG_IMPORT
|
||||
nsCAutoString spec;
|
||||
aURL->GetSpec(spec);
|
||||
printf("\nImporting %s\n", spec.get());
|
||||
#endif
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIParser> parser = do_CreateInstance(kParserCID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -1017,9 +1109,583 @@ nsNavBookmarks::ImportBookmarksHTMLInternal(nsIURI* aURL,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static char kFileIntro[] =
|
||||
"<!DOCTYPE NETSCAPE-Bookmark-file-1>" NS_LINEBREAK
|
||||
// Note: we write bookmarks in UTF-8
|
||||
"<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">" NS_LINEBREAK
|
||||
"<META NAME=\"date\" CONTENT=\"";
|
||||
static char kFileIntro2[] = "\">" NS_LINEBREAK NS_LINEBREAK
|
||||
"<TITLE>Bookmarks</TITLE>" NS_LINEBREAK;
|
||||
static const char kRootIntro[] = "<H1";
|
||||
static const char kCloseRootH1[] = "</H1>" NS_LINEBREAK NS_LINEBREAK;
|
||||
|
||||
static const char kBookmarkIntro[] = "<DL><p>" NS_LINEBREAK;
|
||||
static const char kBookmarkClose[] = "</DL><p>" NS_LINEBREAK;
|
||||
static const char kContainerIntro[] = "<DT><H3";
|
||||
static const char kContainerClose[] = "</H3>" NS_LINEBREAK;
|
||||
static const char kItemOpen[] = "<DT><A";
|
||||
static const char kItemClose[] = "</A>" NS_LINEBREAK;
|
||||
static const char kSeparator[] = "<HR>" NS_LINEBREAK;
|
||||
static const char kQuoteStr[] = "\"";
|
||||
static const char kCloseAngle[] = ">";
|
||||
static const char kIndent[] = " ";
|
||||
|
||||
static const char kPlacesRootAttribute[] = " PLACES_ROOT=\"true\"";
|
||||
static const char kBookmarksRootAttribute[] = " BOOKMARKS_MENU=\"true\"";
|
||||
static const char kToolbarRootAttribute[] = " PERSONAL_TOOLBAR_FOLDER=\"true\"";
|
||||
static const char kIconAttribute[] = " ICON=\"";
|
||||
static const char kIconURIAttribute[] = " ICON_URI=\"";
|
||||
static const char kHrefAttribute[] = " HREF=\"";
|
||||
static const char kFeedURIAttribute[] = " FEEDURL=\"";
|
||||
|
||||
|
||||
// WriteContainerPrologue
|
||||
//
|
||||
// <DL><p>
|
||||
//
|
||||
// Goes after the container header (<H3...) but before the contents
|
||||
|
||||
static nsresult
|
||||
WriteContainerPrologue(const nsCString& aIndent, nsIOutputStream* aOutput)
|
||||
{
|
||||
PRUint32 dummy;
|
||||
nsresult rv = aOutput->Write(aIndent.get(), aIndent.Length(), &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = aOutput->Write(kBookmarkIntro, sizeof(kBookmarkIntro)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// WriteContainerEpilogue
|
||||
//
|
||||
// </DL><p>
|
||||
//
|
||||
// Goes after the container contents to close the container
|
||||
|
||||
static nsresult
|
||||
WriteContainerEpilogue(const nsCString& aIndent, nsIOutputStream* aOutput)
|
||||
{
|
||||
PRUint32 dummy;
|
||||
nsresult rv = aOutput->Write(aIndent.get(), aIndent.Length(), &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = aOutput->Write(kBookmarkClose, sizeof(kBookmarkClose)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// DataToDataURI
|
||||
|
||||
static nsresult
|
||||
DataToDataURI(PRUint8* aData, PRUint32 aDataLen, const nsACString& aMimeType,
|
||||
nsACString& aDataURI)
|
||||
{
|
||||
char* encoded = PL_Base64Encode(NS_REINTERPRET_CAST(const char*, aData),
|
||||
aDataLen, nsnull);
|
||||
if (! encoded)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
aDataURI.AssignLiteral("data:");
|
||||
aDataURI.Append(aMimeType);
|
||||
aDataURI.AppendLiteral(";base64,");
|
||||
aDataURI.Append(encoded);
|
||||
|
||||
nsMemory::Free(encoded);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// WriteFaviconAttribute
|
||||
//
|
||||
// This writes the 'ICON="data:asdlfkjas;ldkfja;skdljfasdf"' attribute for
|
||||
// an item. We special-case chrome favicon URIs by just writing the chrome:
|
||||
// URI.
|
||||
|
||||
static nsresult
|
||||
WriteFaviconAttribute(const nsACString& aURI, nsIOutputStream* aOutput)
|
||||
{
|
||||
nsresult rv;
|
||||
PRUint32 dummy;
|
||||
|
||||
nsFaviconService* faviconService = nsFaviconService::GetFaviconService();
|
||||
NS_ENSURE_TRUE(faviconService, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = NS_NewURI(getter_AddRefs(uri), aURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// get favicon
|
||||
nsCOMPtr<nsIURI> faviconURI;
|
||||
rv = faviconService->GetFaviconForPage(uri, getter_AddRefs(faviconURI));
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE)
|
||||
return NS_OK; // no favicon
|
||||
NS_ENSURE_SUCCESS(rv, rv); // anything else is error
|
||||
|
||||
nsCAutoString faviconScheme;
|
||||
nsCAutoString faviconSpec;
|
||||
rv = faviconURI->GetSpec(faviconSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = faviconURI->GetScheme(faviconScheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// write favicon URI: 'ICON_URI="..."'
|
||||
rv = aOutput->Write(kIconURIAttribute, sizeof(kIconURIAttribute)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = aOutput->Write(faviconSpec.get(), faviconSpec.Length(), &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (! faviconScheme.EqualsLiteral("chrome")) {
|
||||
// only store data for non-chrome URIs
|
||||
|
||||
// get the data - BE SURE TO FREE
|
||||
nsCAutoString mimeType;
|
||||
PRUint32 dataLen;
|
||||
PRUint8* data;
|
||||
rv = faviconService->GetFaviconData(faviconURI, mimeType, &dataLen, &data);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (dataLen > 0) {
|
||||
// convert to URI
|
||||
nsCString faviconContents;
|
||||
rv = DataToDataURI(data, dataLen, mimeType, faviconContents);
|
||||
nsMemory::Free(data);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = aOutput->Write(kIconAttribute, sizeof(kIconAttribute)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = aOutput->Write(faviconContents.get(), faviconContents.Length(), &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavBookmarks::WriteContainer
|
||||
//
|
||||
// Writes out all the necessary parts of a bookmarks folder.
|
||||
|
||||
nsresult
|
||||
nsNavBookmarks::WriteContainer(PRInt64 aFolder, const nsCString& aIndent,
|
||||
nsIOutputStream* aOutput)
|
||||
{
|
||||
nsresult rv = WriteContainerHeader(aFolder, aIndent, aOutput);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// FIXME bug 334758: write container description here as a <DD>
|
||||
|
||||
rv = WriteContainerPrologue(aIndent, aOutput);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = WriteContainerContents(aFolder, aIndent, aOutput);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = WriteContainerEpilogue(aIndent, aOutput);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
|
||||
|
||||
// nsNavBookmarks::WriteContainerHeader
|
||||
//
|
||||
// This writes '<DL><H3>Title</H3>'
|
||||
// Remember folders can also have favicons, which we put in the H3 tag
|
||||
|
||||
nsresult
|
||||
nsNavBookmarks::WriteContainerHeader(PRInt64 aFolder, const nsCString& aIndent,
|
||||
nsIOutputStream* aOutput)
|
||||
{
|
||||
PRUint32 dummy;
|
||||
nsresult rv;
|
||||
|
||||
// indent
|
||||
if (! aIndent.IsEmpty()) {
|
||||
rv = aOutput->Write(aIndent.get(), aIndent.Length(), &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// "<DL H3"
|
||||
rv = aOutput->Write(kContainerIntro, sizeof(kContainerIntro)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// " PERSONAL_TOOLBAR_FOLDER="true"", etc.
|
||||
if (aFolder == mRoot) {
|
||||
rv = aOutput->Write(kPlacesRootAttribute, sizeof(kPlacesRootAttribute)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
} else if (aFolder == mBookmarksRoot) {
|
||||
rv = aOutput->Write(kBookmarksRootAttribute, sizeof(kBookmarksRootAttribute)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
} else if (aFolder == mToolbarRoot) {
|
||||
rv = aOutput->Write(kToolbarRootAttribute, sizeof(kToolbarRootAttribute)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// favicon (most folders won't have one)
|
||||
nsCOMPtr<nsIURI> folderURI;
|
||||
rv = GetFolderURI(aFolder, getter_AddRefs(folderURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCAutoString folderSpec;
|
||||
rv = folderURI->GetSpec(folderSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = WriteFaviconAttribute(folderSpec, aOutput);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// ">"
|
||||
rv = aOutput->Write(kCloseAngle, sizeof(kCloseAngle)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// title
|
||||
rv = WriteContainerTitle(aFolder, aOutput);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// "</H3>\n"
|
||||
rv = aOutput->Write(kContainerClose, sizeof(kContainerClose)-1, &dummy);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
// nsNavBookmarks::WriteContainerTitle
|
||||
//
|
||||
// Retrieves, escaped and writes the container title to the stream.
|
||||
|
||||
nsresult
|
||||
nsNavBookmarks::WriteContainerTitle(PRInt64 aFolder, nsIOutputStream* aOutput)
|
||||
{
|
||||
nsAutoString title;
|
||||
nsresult rv = GetFolderTitle(aFolder, title);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
char* escapedTitle = nsEscapeHTML(NS_ConvertUTF16toUTF8(title).get());
|
||||
if (escapedTitle) {
|
||||
PRUint32 dummy;
|
||||
rv = aOutput->Write(escapedTitle, strlen(escapedTitle), &dummy);
|
||||
nsMemory::Free(escapedTitle);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// WriteItem
|
||||
//
|
||||
// "<DT><A HREF="..." ICON="...">Name</A>"
|
||||
|
||||
static nsresult
|
||||
WriteItem(nsNavHistoryResultNode* aItem, const nsCString& aIndent,
|
||||
nsIOutputStream* aOutput)
|
||||
{
|
||||
PRUint32 dummy;
|
||||
nsresult rv;
|
||||
|
||||
// indent
|
||||
if (! aIndent.IsEmpty()) {
|
||||
rv = aOutput->Write(aIndent.get(), aIndent.Length(), &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// '<DT><A'
|
||||
rv = aOutput->Write(kItemOpen, sizeof(kItemOpen)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// ' HREF="http://..."' - note that we need to call GetURI on the result
|
||||
// node because some nodes (eg queries) generate this lazily.
|
||||
rv = aOutput->Write(kHrefAttribute, sizeof(kHrefAttribute)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
nsCAutoString uri;
|
||||
rv = aItem->GetUri(uri);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = aOutput->Write(uri.get(), uri.Length(), &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// ' ICON="..."'
|
||||
rv = WriteFaviconAttribute(uri, aOutput);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// FIXME bug 334408: write last character set here
|
||||
|
||||
// '>'
|
||||
rv = aOutput->Write(kCloseAngle, sizeof(kCloseAngle)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// title
|
||||
char* escapedTitle = nsEscapeHTML(aItem->mTitle.get());
|
||||
if (escapedTitle) {
|
||||
rv = aOutput->Write(escapedTitle, strlen(escapedTitle), &dummy);
|
||||
nsMemory::Free(escapedTitle);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// '</A>\n'
|
||||
rv = aOutput->Write(kItemClose, sizeof(kItemClose)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// FIXME bug 334758: write item description here as a <DD>
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// WriteLivemark
|
||||
//
|
||||
// Similar to WriteItem, this has an additional FEEDURL attribute and
|
||||
// the HREF is optional and points to the source page.
|
||||
|
||||
nsresult
|
||||
nsNavBookmarks::WriteLivemark(PRInt64 aFolderId, const nsCString& aIndent,
|
||||
nsIOutputStream* aOutput)
|
||||
{
|
||||
PRUint32 dummy;
|
||||
nsresult rv;
|
||||
|
||||
nsLivemarkService* livemarkService = nsLivemarkService::GetLivemarkService();
|
||||
NS_ENSURE_TRUE(livemarkService, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// indent
|
||||
if (! aIndent.IsEmpty()) {
|
||||
rv = aOutput->Write(aIndent.get(), aIndent.Length(), &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// '<DT><A'
|
||||
rv = aOutput->Write(kItemOpen, sizeof(kItemOpen)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// get feed URI
|
||||
nsCOMPtr<nsIURI> feedURI;
|
||||
rv = livemarkService->GetFeedURI(aFolderId, getter_AddRefs(feedURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCString feedSpec;
|
||||
rv = feedURI->GetSpec(feedSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// write feed URI
|
||||
rv = aOutput->Write(kFeedURIAttribute, sizeof(kFeedURIAttribute)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = aOutput->Write(feedSpec.get(), feedSpec.Length(), &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// get the optional site URI
|
||||
nsCOMPtr<nsIURI> siteURI;
|
||||
rv = livemarkService->GetSiteURI(aFolderId, getter_AddRefs(siteURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (siteURI) {
|
||||
nsCString siteSpec;
|
||||
rv = siteURI->GetSpec(siteSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// write site URI
|
||||
rv = aOutput->Write(kHrefAttribute, sizeof(kHrefAttribute)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = aOutput->Write(siteSpec.get(), siteSpec.Length(), &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = aOutput->Write(kQuoteStr, sizeof(kQuoteStr)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// '>'
|
||||
rv = aOutput->Write(kCloseAngle, sizeof(kCloseAngle)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// title
|
||||
rv = WriteContainerTitle(aFolderId, aOutput);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// '</A>\n'
|
||||
rv = aOutput->Write(kItemClose, sizeof(kItemClose)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// WriteSeparator
|
||||
//
|
||||
// "<HR>"
|
||||
|
||||
nsresult
|
||||
WriteSeparator(const nsCString& aIndent, nsIOutputStream* aOutput)
|
||||
{
|
||||
PRUint32 dummy;
|
||||
nsresult rv;
|
||||
|
||||
// indent
|
||||
if (! aIndent.IsEmpty()) {
|
||||
rv = aOutput->Write(aIndent.get(), aIndent.Length(), &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
rv = aOutput->Write(kSeparator, sizeof(kSeparator)-1, &dummy);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
// nsNavBookmarks::WriteContainerContents
|
||||
//
|
||||
// The indent here is the indent of the parent. We will add an additional
|
||||
// indent before writing data.
|
||||
|
||||
nsresult
|
||||
nsNavBookmarks::WriteContainerContents(PRInt64 aFolder, const nsCString& aIndent,
|
||||
nsIOutputStream* aOutput)
|
||||
{
|
||||
nsCString myIndent = aIndent;
|
||||
myIndent.Append(kIndent);
|
||||
|
||||
nsNavHistory* historyService = nsNavHistory::GetHistoryService();
|
||||
NS_ENSURE_TRUE(historyService, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// get empty options
|
||||
nsCOMPtr<nsINavHistoryQueryOptions> optionsInterface;
|
||||
nsresult rv = historyService->GetNewQueryOptions(getter_AddRefs(optionsInterface));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// QueryFolderChildren requires a concrete options
|
||||
nsCOMPtr<nsNavHistoryQueryOptions> options = do_QueryInterface(optionsInterface);
|
||||
NS_ENSURE_TRUE(options, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// get contents of folder
|
||||
nsCOMArray<nsNavHistoryResultNode> items;
|
||||
rv = QueryFolderChildren(aFolder, options, &items);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// write each item
|
||||
for (PRInt32 i = 0; i < items.Count(); i ++) {
|
||||
if (items[i]->IsFolder()) {
|
||||
// bookmarks folder
|
||||
PRInt64 folderId = items[i]->GetAsFolder()->mFolderId;
|
||||
if (aFolder == mRoot && (folderId == mToolbarRoot ||
|
||||
folderId == mBookmarksRoot)) {
|
||||
// don't write out the bookmarks menu or the toolbar folder from the
|
||||
// places root. When writing to bookmarks.html, these are reparented
|
||||
// to the menu, which is the root of the namespace. This provides
|
||||
// better backwards compatability.
|
||||
continue;
|
||||
}
|
||||
|
||||
// it could be a regular folder or it could be a livemark
|
||||
nsLivemarkService* livemarkService = nsLivemarkService::GetLivemarkService();
|
||||
NS_ENSURE_TRUE(livemarkService, NS_ERROR_UNEXPECTED);
|
||||
PRBool isLivemark;
|
||||
rv = livemarkService->IsLivemark(folderId, &isLivemark);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (isLivemark)
|
||||
rv = WriteLivemark(folderId, myIndent, aOutput);
|
||||
else
|
||||
rv = WriteContainer(folderId, myIndent, aOutput);
|
||||
} else if (items[i]->IsSeparator()) {
|
||||
rv = WriteSeparator(myIndent, aOutput);
|
||||
} else {
|
||||
rv = WriteItem(items[i], myIndent, aOutput);
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
// nsNavBookmarks::ExportBookmarksHTML
|
||||
//
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavBookmarks::ExportBookmarksHTML(nsIURI* aURL)
|
||||
nsNavBookmarks::ExportBookmarksHTML(nsIFile* aBookmarksFile)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
if (! aBookmarksFile)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
// get a safe output stream, so we don't clobber the bookmarks file unless
|
||||
// all the writes succeeded.
|
||||
nsCOMPtr<nsIOutputStream> out;
|
||||
nsresult rv = NS_NewSafeLocalFileOutputStream(getter_AddRefs(out),
|
||||
aBookmarksFile,
|
||||
PR_WRONLY | PR_CREATE_FILE,
|
||||
/*octal*/ 0600,
|
||||
0);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// We need a buffered output stream for performance.
|
||||
// See bug 202477.
|
||||
nsCOMPtr<nsIOutputStream> strm;
|
||||
rv = NS_NewBufferedOutputStream(getter_AddRefs(strm), out, 4096);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// file header
|
||||
PRUint32 dummy;
|
||||
rv = strm->Write(kFileIntro, sizeof(kFileIntro)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// generated time
|
||||
PRExplodedTime time;
|
||||
PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &time);
|
||||
char timeBuf[128];
|
||||
PRUint32 ret = PR_FormatTime(timeBuf, sizeof(timeBuf),
|
||||
"%a, %d %b %Y %H:%M:%S %z", &time);
|
||||
if (ret > 0 && ret < sizeof(timeBuf)) {
|
||||
rv = strm->Write(timeBuf, strlen(timeBuf), &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
// rest of file header
|
||||
rv = strm->Write(kFileIntro2, sizeof(kFileIntro2)-1, &dummy);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// '<H1'
|
||||
rv = strm->Write(kRootIntro, sizeof(kRootIntro)-1, &dummy); // <H1
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// bookmarks menu favicon
|
||||
nsCOMPtr<nsIURI> folderURI;
|
||||
rv = GetFolderURI(mBookmarksRoot, getter_AddRefs(folderURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCAutoString folderSpec;
|
||||
rv = folderURI->GetSpec(folderSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = WriteFaviconAttribute(folderSpec, strm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// '>Bookmarks</H1>
|
||||
rv = strm->Write(kCloseAngle, sizeof(kCloseAngle)-1, &dummy); // >
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = WriteContainerTitle(mBookmarksRoot, strm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = strm->Write(kCloseRootH1, sizeof(kCloseRootH1)-1, &dummy); // </H1>
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// prologue
|
||||
rv = WriteContainerPrologue(EmptyCString(), strm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// indents
|
||||
nsCAutoString indent;
|
||||
indent.Assign(kIndent);
|
||||
|
||||
// places root
|
||||
rv = WriteContainer(mRoot, indent, strm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// toolbar
|
||||
rv = WriteContainer(mToolbarRoot, indent, strm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// bookmarks menu contents
|
||||
rv = WriteContainerContents(mBookmarksRoot, EmptyCString(), strm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// epilogue
|
||||
rv = WriteContainerEpilogue(EmptyCString(), strm);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// commit the write
|
||||
nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(strm, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return safeStream->Finish();
|
||||
}
|
||||
|
|
|
@ -88,6 +88,16 @@ public:
|
|||
nsLivemarkService();
|
||||
nsresult Init();
|
||||
|
||||
static nsLivemarkService* GetLivemarkService() {
|
||||
if (!sInstance) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsILivemarkService> serv(do_GetService(NS_LIVEMARKSERVICE_CONTRACTID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, nsnull);
|
||||
NS_ASSERTION(sInstance, "Should have static instance pointer now");
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
// These functions are called by the livemarks feed loader
|
||||
// to set the livemark children.
|
||||
nsresult DeleteLivemarkChildren(PRInt64 aLivemarkFolderId);
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#include "nsNavHistoryResult.h" // need for Int64 hashtable
|
||||
#include "nsBrowserCompsCID.h"
|
||||
|
||||
class nsIOutputStream;
|
||||
|
||||
class nsNavBookmarks : public nsINavBookmarksService,
|
||||
public nsINavHistoryObserver
|
||||
{
|
||||
|
@ -240,6 +242,15 @@ private:
|
|||
nsresult ImportBookmarksHTMLInternal(nsIURI* aURL,
|
||||
PRBool aAllowRootChanges,
|
||||
PRInt64 aFolder);
|
||||
nsresult WriteContainer(PRInt64 aFolder, const nsCString& aIndent,
|
||||
nsIOutputStream* aOutput);
|
||||
nsresult WriteContainerHeader(PRInt64 aFolder, const nsCString& aIndent,
|
||||
nsIOutputStream* aOutput);
|
||||
nsresult WriteContainerTitle(PRInt64 aFolder, nsIOutputStream* aOutput);
|
||||
nsresult WriteLivemark(PRInt64 aFolderId, const nsCString& aIndent,
|
||||
nsIOutputStream* aOutput);
|
||||
nsresult WriteContainerContents(PRInt64 aFolder, const nsCString& aIndent,
|
||||
nsIOutputStream* aOutput);
|
||||
};
|
||||
|
||||
struct nsBookmarksUpdateBatcher
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
<DD>Add bookmarks to this folder to see them displayed on the Bookmarks Toolbar
|
||||
<DL><p>
|
||||
</DL><p>
|
||||
<DT><A HREF="place:annotation=livemark/feedURI">Subscriptions</A>
|
||||
<DT><A HREF="place:&annotation=livemark%2FfeedURI">Subscriptions</A>
|
||||
<DD>Shows all Subscribed Feeds
|
||||
<DL><p>
|
||||
</DL><p>
|
||||
</DL><p>
|
||||
|
|
|
@ -3,13 +3,23 @@
|
|||
It will be read and overwritten.
|
||||
DO NOT EDIT! -->
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
|
||||
<TITLE>Bookmarks and History</TITLE>
|
||||
<H1 PLACES_ROOT="true">Bookmarks and History</H1>
|
||||
<TITLE>Bookmarks</TITLE>
|
||||
<H1>Bookmarks</H1>
|
||||
|
||||
<DL><p>
|
||||
<DT><A HREF="place:&beginTime=-2592000000000&beginTimeRef=1&endTime=7200000000&endTimeRef=2&sort=4&type=1">History</A>
|
||||
<DD>Shows all browsing history
|
||||
<DT><H3 BOOKMARKS_MENU="true">Bookmarks Menu</H3>
|
||||
<DT><H3 PLACES_ROOT="true">Places</H3>
|
||||
<DL><p>
|
||||
<DT><H3>Firefox and Mozilla Links</H3>
|
||||
<DL><p>
|
||||
<DT><A HREF="http://start.mozilla.org/firefox" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" LAST_CHARSET="ISO-8859-1">Firefox Start Page</A>
|
||||
<DT><A HREF="http://www.mozilla.org/products/firefox/central.html" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" LAST_CHARSET="ISO-8859-1">Firefox Central</A>
|
||||
<DT><A HREF="http://addons.mozilla.org/?application=firefox" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" LAST_CHARSET="UTF-8">Themes and Extensions</A>
|
||||
<DT><A HREF="http://getfirefox.com/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" LAST_CHARSET="ISO-8859-1">Firefox Product Page</A>
|
||||
<DT><A HREF="http://www.mozilla.org/" LAST_VISIT="1133213523" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" LAST_CHARSET="UTF-8">The Mozilla web site</A>
|
||||
<DT><A HREF="http://www.mozillazine.org/" ICON="data:image/x-icon;base64,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" LAST_CHARSET="ISO-8859-1">MozillaZine</A>
|
||||
<DT><A HREF="http://store.mozilla.org/" ICON="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A1NTU/9TU1P/U1NT/1NTU/9TU1P/U1NT/1NTU/9TU1P/U1NT/////AP///wD///8A////AP///wD///8Ag4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/1NTU/9TU1P////8A////AP///wD///8Ag4OD/83Nzf/09PT/8/Pz//Pz8//w8PD/7e3t/+np6f/n5+f/wcHB/4ODg//U1NT/////AP///wD///8A////AIODg//19fX/9fX1//T09P/09PT/8vLy/+7u7v/q6ur/6Ojo/+Tk5P+Dg4P/1NTU/////wD///8A////AP///wCDg4P/9vb2//b29v/19fX/9fX1//T09P/w8PD/7Ozs/+np6f/l5eX/g4OD/9TU1P////8A////AP///wD///8Ag4OD//f39//39/f/9vb2//b29v/19fX/8vLy/+3t7f/p6en/5ubm/4ODg//U1NT/////AP///wD///8A////AIODg//4+Pj/+Pj4/2t2x//39/f/T1y+//Pz8/92f8n/3d7m/+fn5/+Dg4P/1NTU/////wD///8A////ANTU1P+Dg4P/+vr6//r6+v8YKav/srjh/xgpq/+wtd7/GCmr/+3t7f/o6Oj/g4OD/9TU1P/U1NT/1NTU/4ODg/+Dg4P/g4OD//v7+//6+vr/QlC6/2x3yP+JkdL/a3XH/0JQuv/u7u7/6urq/4ODg/+Dg4P/g4OD/9TU1P+Dg4P//Pz8/6urq//8/Pz/+/v7/1Bdv/80Q7X/7e72/zRDtf9QXb//7+/v/+vr6/+kpKT/5+fn/4ODg//U1NT/g4OD//z8/P/S0tL//Pz8//z8/P9QXb//X2rE//z8/P9fasT/UF2///Hx8f/t7e3/xcXF/+jo6P+Dg4P/1NTU/4ODg//9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+vr6//f39//z8/P/7u7u/+vr6//p6en/g4OD/9TU1P+Dg4P//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//z8/P/4+Pj/9PT0//Dw8P/t7e3/6+vr/4ODg/////8A////AIODg/////////////////+Dg4P/g4OD/4ODg/+Dg4P/g4OD//b29v/y8vL/7+/v/4ODg/////8A////AP///wD///8Ag4OD/4ODg/+Dg4P/////AP///wD///8A////AP///wCDg4P/g4OD/4ODg/////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A8AcAAOADAADAAwAAwAMAAMADAADAAwAAwAMAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAIADAADHxwAA//8AAA==" LAST_CHARSET="ISO-8859-1">Mozilla Store</A>
|
||||
<DT><A HREF="http://www.spreadfirefox.com/" LAST_CHARSET="UTF-8">Get Involved - Help spread Firefox!</A>
|
||||
</DL><p>
|
||||
</DL><p>
|
||||
<DT><H3 PERSONAL_TOOLBAR_FOLDER="true">Bookmarks Toolbar</H3>
|
||||
<DD>Add bookmarks to this folder to see them displayed on the Bookmarks Toolbar
|
||||
|
@ -17,19 +27,4 @@
|
|||
<DT><A HREF="http://www.mozilla.com/products/firefox/central.html" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" LAST_CHARSET="ISO-8859-1" ID="rdf:#$GvPhC3">Getting Started</A>
|
||||
<DT><A HREF="http://fxfeeds.mozilla.com/" LAST_MODIFIED="1094668003" FEEDURL="http://fxfeeds.mozilla.com/rss20.xml" ID="rdf:#$HvPhC3">Latest Headlines</A>
|
||||
</DL><p>
|
||||
<DT><A HREF="place:annotation=livemark/feedURI">Subscriptions</A>
|
||||
<DD>Shows all Subscribed Feeds
|
||||
<DL><p>
|
||||
</DL><p>
|
||||
<DT><H3>Firefox and Mozilla Links</H3>
|
||||
<DL><p>
|
||||
<DT><A HREF="http://start.mozilla.org/firefox" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" LAST_CHARSET="ISO-8859-1">Firefox Start Page</A>
|
||||
<DT><A HREF="http://www.mozilla.org/products/firefox/central.html" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" LAST_CHARSET="ISO-8859-1">Firefox Central</A>
|
||||
<DT><A HREF="http://addons.mozilla.org/?application=firefox" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" LAST_CHARSET="UTF-8">Themes and Extensions</A>
|
||||
<DT><A HREF="http://getfirefox.com/" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" LAST_CHARSET="ISO-8859-1">Firefox Product Page</A>
|
||||
<DT><A HREF="http://www.mozilla.org/" LAST_VISIT="1133213523" ICON="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==" LAST_CHARSET="UTF-8">The Mozilla web site</A>
|
||||
<DT><A HREF="http://www.mozillazine.org/" ICON="data:image/x-icon;base64,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" LAST_CHARSET="ISO-8859-1">MozillaZine</A>
|
||||
<DT><A HREF="http://store.mozilla.org/" ICON="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A1NTU/9TU1P/U1NT/1NTU/9TU1P/U1NT/1NTU/9TU1P/U1NT/////AP///wD///8A////AP///wD///8Ag4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4ODg/+Dg4P/1NTU/9TU1P////8A////AP///wD///8Ag4OD/83Nzf/09PT/8/Pz//Pz8//w8PD/7e3t/+np6f/n5+f/wcHB/4ODg//U1NT/////AP///wD///8A////AIODg//19fX/9fX1//T09P/09PT/8vLy/+7u7v/q6ur/6Ojo/+Tk5P+Dg4P/1NTU/////wD///8A////AP///wCDg4P/9vb2//b29v/19fX/9fX1//T09P/w8PD/7Ozs/+np6f/l5eX/g4OD/9TU1P////8A////AP///wD///8Ag4OD//f39//39/f/9vb2//b29v/19fX/8vLy/+3t7f/p6en/5ubm/4ODg//U1NT/////AP///wD///8A////AIODg//4+Pj/+Pj4/2t2x//39/f/T1y+//Pz8/92f8n/3d7m/+fn5/+Dg4P/1NTU/////wD///8A////ANTU1P+Dg4P/+vr6//r6+v8YKav/srjh/xgpq/+wtd7/GCmr/+3t7f/o6Oj/g4OD/9TU1P/U1NT/1NTU/4ODg/+Dg4P/g4OD//v7+//6+vr/QlC6/2x3yP+JkdL/a3XH/0JQuv/u7u7/6urq/4ODg/+Dg4P/g4OD/9TU1P+Dg4P//Pz8/6urq//8/Pz/+/v7/1Bdv/80Q7X/7e72/zRDtf9QXb//7+/v/+vr6/+kpKT/5+fn/4ODg//U1NT/g4OD//z8/P/S0tL//Pz8//z8/P9QXb//X2rE//z8/P9fasT/UF2///Hx8f/t7e3/xcXF/+jo6P+Dg4P/1NTU/4ODg//9/f3//f39//39/f/9/f3//f39//39/f/9/f3/+vr6//f39//z8/P/7u7u/+vr6//p6en/g4OD/9TU1P+Dg4P//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//z8/P/4+Pj/9PT0//Dw8P/t7e3/6+vr/4ODg/////8A////AIODg/////////////////+Dg4P/g4OD/4ODg/+Dg4P/g4OD//b29v/y8vL/7+/v/4ODg/////8A////AP///wD///8Ag4OD/4ODg/+Dg4P/////AP///wD///8A////AP///wCDg4P/g4OD/4ODg/////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A8AcAAOADAADAAwAAwAMAAMADAADAAwAAwAMAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAIADAADHxwAA//8AAA==" LAST_CHARSET="ISO-8859-1">Mozilla Store</A>
|
||||
<DT><A HREF="http://www.spreadfirefox.com/" LAST_CHARSET="UTF-8">Get Involved - Help spread Firefox!</A>
|
||||
</DL><p>
|
||||
</DL><p>
|
||||
|
|
Загрузка…
Ссылка в новой задаче