home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-
- #include "bkmks.h"
- #include "net.h"
- #include "xp_mcom.h"
- #include "client.h"
- #include "msgcom.h"
- #include "undo.h"
- #include "xp_hash.h"
- #include "xpgetstr.h"
- #include "glhist.h"
- #include "libi18n.h"
- #include "xp_qsort.h"
- #include "intl_csi.h"
-
- /* N.B. If you add code to this file, make sure it still builds on win16 debug - its
- code segment is too big.
- */
-
- #define INTL_SORT 1
- #ifdef INTL_SORT /* Added by ftang */
- #include "xplocale.h"
- #endif
-
- extern int MK_OUT_OF_MEMORY;
-
- extern int XP_BKMKS_BOOKMARKS_CHANGED;
- extern int XP_BKMKS_ADDRESSBOOK_CHANGED;
- extern int XP_BKMKS_BOOKMARKS_CONFLICT;
- extern int XP_BKMKS_ADDRESSBOOK_CONFLICT;
- extern int XP_BKMKS_CANT_WRITE_ADDRESSBOOK;
- extern int XP_BKMKS_CANT_WRITE_BOOKMARKS;
-
- /* added by L10N team */
- extern int XP_BKMKS_HOURS_AGO;
- extern int XP_BKMKS_DAYS_AGO;
- extern int XP_BKMKS_COUNTALIASES_MANY;
- extern int XP_BKMKS_COUNTALIASES_ONE;
- extern int XP_BKMKS_COUNTALIASES_NONE;
- extern int XP_BKMKS_INVALID_NICKNAME;
- extern int XP_BKMKS_NICKNAME_ALREADY_EXISTS;
- extern int XP_BKMKS_REMOVE_THIS_ITEMS_ALIASES;
- extern int XP_BKMKS_REMOVE_SOME_ITEMS_ALIASES;
- extern int XP_BKMKS_AUTOGENERATED_FILE;
- extern int XP_BKMKS_READ_AND_OVERWRITE;
- extern int XP_BKMKS_DO_NOT_EDIT;
- extern int XP_BKMKS_NEW_HEADER;
- extern int XP_BKMKS_NEW_BOOKMARK;
- extern int XP_BKMKS_NOT_FOUND;
- extern int XP_BKMKS_OPEN_BKMKS_FILE;
- extern int XP_BKMKS_IMPORT_BKMKS_FILE;
- extern int XP_BKMKS_IMPORT_ADDRBOOK;
- extern int XP_BKMKS_SAVE_BKMKS_FILE;
- extern int XP_BKMKS_SAVE_ADDRBOOK;
- extern int XP_BKMKS_LESS_THAN_ONE_HOUR_AGO;
-
-
- extern int XP_BKMKS_SOMEONE_S_BOOKMARKS; /* "%s%s's Bookmarks%s" */
- extern int XP_BKMKS_PERSONAL_BOOKMARKS; /* "%sPersonal Bookmarks%s" */
- extern int XP_BKMKS_SOMEONE_S_ADDRESSBOOK; /* "%s%s's Addressbook%s" */
- extern int XP_BKMKS_PERSONAL_ADDRESSBOOK; /* "%sPersonal Addressbook%s" */
-
- extern int XP_BKMKS_BOOKMARK;
- extern int XP_BKMKS_ENTRY;
- extern int XP_BKMKS_SECONDS;
- extern int XP_BKMKS_MINUTES;
- extern int XP_BKMKS_HOURS_MINUTES;
-
- extern int XP_BKMKS_HEADER;
- extern int XP_ADDRBOOK_HEADER;
-
-
- #define SECONDS_PER_DAY 86400L
- #define BMLIST_COOKIE "<!DOCTYPE NETSCAPE-Bookmark-file-1>"
- #define BM_ADDR_LIST_COOKIE "<!DOCTYPE NETSCAPE-Addressbook-file-1>"
- #define READ_BUFFER_SIZE 2048
- #define DEF_NAME "Personal Bookmarks" /* L10N? This doesn't seem to be used. */
-
- #ifdef FREEIF
- #undef FREEIF
- #endif
- #define FREEIF(obj) do { if (obj) { XP_FREE (obj); obj = 0; }} while (0)
-
- #define BM_ATTR_FOLDED 0x0001
- #define BM_ATTR_SELECTED 0x0002
- #define BM_ATTR_ISNEW 0x0004
- #define BM_ATTR_FINDAFF 0x0008 /* This entry is temporarily unfolded only
- as a result of the last find
- operation. */
- #define BM_ATTR_HASALIASES 0x0010 /* Actually, being set only means that
- this entry *might* have aliases. But
- if an entry has aliases, this bit is
- definitely set. */
- #define BM_ATTR_MARKED 0x0020 /* Random bit to temporarily mark a bunch of
- items. */
- #define BM_ATTR_CHECKING 0x0040 /* In the midst of checking whether this
- entry has changed. */
-
-
- #define BM_ISHEADER(bmStruct) \
- ((bmStruct) && ((bmStruct)->type == BM_TYPE_HEADER))
-
- #define BM_ISURL(bmStruct) \
- ((bmStruct) && ((bmStruct)->type == BM_TYPE_URL))
-
- #define BM_ISADDRESS(bmStruct) \
- ((bmStruct) && ((bmStruct)->type == BM_TYPE_ADDRESS))
-
- #define BM_ISSEPARATOR(bmStruct) \
- ((bmStruct) && ((bmStruct)->type == BM_TYPE_SEPARATOR))
-
- #define BM_ISALIAS(bmStruct) \
- ((bmStruct) && ((bmStruct)->type == BM_TYPE_ALIAS))
-
- #define BM_ISFOLDED(bmStruct) \
- ((bmStruct) && ((bmStruct)->flags & BM_ATTR_FOLDED))
-
- #define BM_ISSELECTED(bmStruct) \
- ((bmStruct) && ((bmStruct)->flags & BM_ATTR_SELECTED))
-
- #define BM_SETFLAG(bmStruct, flag) \
- ((bmStruct) ? ((bmStruct)->flags |= (flag)) : 0)
-
- #define BM_CLEARFLAG(bmStruct, flag) \
- ((bmStruct) ? ((bmStruct)->flags &= ~(flag)) : 0)
-
- static int32 g_iNaturalIndexPool = 0;
-
- struct BM_Entry_struct
- {
- BM_Type type;
-
- uint16 flags;
- BM_Entry* next;
- BM_Entry* parent;
- char* name;
- char* description;
- BM_Date addition_date;
- int32 iNaturalIndex; /* Index for user arranged "sort" */
- char* nickname; /* Used only by address book, alas. */
-
- union {
- struct BM_Header {
- char* target; /* target */
- BM_Entry* children; /* a linked list of my children */
- uint32 childCount; /* the number of "children" */
- BM_Entry* lastChild; /* the last child in "children" */
- } header;
- struct BM_Url {
- char* address; /* address */
- char* target; /* target */
- char* content_type; /* content-type */
- BM_Date last_visit; /* when last visited */
- BM_Date last_modified; /* when the contents of the URL was last
- modified. */
- } url;
- struct BM_Address {
- char* address; /* e-mail address */
- } address;
- struct BM_Alias {
- BM_Entry* original; /* the original bm */
- } alias;
- } d;
- };
-
-
- typedef struct BM_Frame {
- BM_Entry* gBookmarks; /* root of the tree */
- XP_Bool gBookmarksModified; /* TRUE if the tree is modified */
- int32 gCount; /* number of entries in tree. If
- negative, then need to be
- recalculated. */
- int32 gVisCount; /* number of visible entries. If
- negative, then need to be
- recalculated. */
- int32 gSelectionCount; /* number of selected items. If
- negative, then we're out of sync,
- call bm_SyncSelection to
- synchronize. */
- uint32 gSelectionMask; /* what types of items are selected
- (invalid if gSelectionCount is
- negative.)*/
- BM_FindInfo* gFindInfo; /* information for the find dialog */
- char* gFile; /* the file this data is from */
- void* gTemporary;
- void* feData;
- int32 max_depth; /* The number of levels in the heirarchy that
- we currently display. (If zero, then we
- don't know. */
- UndoState* undo;
- MWContext* next; /* Next bookmarks context in master linked list. */
- XP_Bool unfoldedForFind; /* TRUE if some headers have been unfolded
- as the result of a find operation. The
- headers in question will have the
- BM_ATTR_FINDAFF flag set.*/
-
- BM_SortType enSortType; /* the sort field (a column or natural) */
- XP_Bool bSorting;
- XP_HashTable aliasTable;
- XP_HashTable nicknameTable;
- int aliasID;
- XP_Bool errorSavingBookmarks;
-
- int32 batch_depth;
- int32 first_update_line;
- int32 last_update_line;
-
- void* savetimer;
-
- BM_Entry* lastSelectedItem;
-
- BM_Entry* menuheader; /* Which header to use as the menu bar. */
- BM_Entry* addheader; /* Which entry to add new items into. */
-
- XP_StatStruct laststat; /* Stat of the file when we loaded it in. */
-
-
-
- struct BM_WhatsChangedInfo {
- int32 total;
- int32 numreached;
- int32 numchanged;
- time_t starttime;
- } whatschanged;
-
- } BM_Frame;
-
-
- #define CHKCONTEXT(context) \
- XP_ASSERT(context != NULL && (context->type == MWContextAddressBook || \
- context->type == MWContextBookmarks) && \
- context->bmframe != NULL); \
- if (!context || (context->type != MWContextAddressBook && \
- context->type != MWContextBookmarks) || \
- !context->bmframe) return 0;
-
- #define CHKCONTEXTVOID(context) \
- XP_ASSERT(context != NULL && (context->type == MWContextAddressBook || \
- context->type == MWContextBookmarks) && \
- context->bmframe != NULL); \
- if (!context || (context->type != MWContextAddressBook && \
- context->type != MWContextBookmarks) || \
- !context->bmframe) return;
-
-
- /* Should probably be a macro, but putting the assert in the macro and
- making this still be easy to use is just too painful. */
- static BM_Frame*
- GETFRAME(MWContext* context)
- {
- XP_ASSERT(context &&
- (context->type == MWContextBookmarks ||
- context->type == MWContextAddressBook) &&
- context->bmframe != NULL);
- return (context && (context->type == MWContextBookmarks ||
- context->type == MWContextAddressBook))
- ? context->bmframe : NULL;
- }
-
-
- static void bm_CancelLastFind(MWContext* context);
- static void bm_InsertItemAfter(MWContext* context, BM_Entry* insert_after,
- BM_Entry* insertee, XP_Bool sync);
- static void bm_SortSelected(MWContext* context, BM_SortType enSortType);
- static void bm_SyncCount(MWContext* context);
- static void bm_AddChildToHeaderSorted(MWContext* context, BM_Entry* parent,
- BM_Entry* child);
- static void bm_SortSilent(MWContext* context, BM_SortType enSortType );
-
-
-
- XP_Bool
- BM_IsHeader(BM_Entry* entry)
- {
- return BM_ISHEADER(entry);
- }
-
- XP_Bool
- BM_IsUrl(BM_Entry* entry)
- {
- return BM_ISURL(entry);
- }
-
- XP_Bool
- BM_IsAddress(BM_Entry* entry)
- {
- return BM_ISADDRESS(entry);
- }
-
- XP_Bool
- BM_IsSeparator(BM_Entry* entry)
- {
- return BM_ISSEPARATOR(entry);
- }
-
- XP_Bool
- BM_IsAlias(BM_Entry* entry)
- {
- return BM_ISALIAS(entry);
- }
-
- XP_Bool
- BM_IsFolded(BM_Entry* entry)
- {
- return BM_ISFOLDED(entry);
- }
-
- XP_Bool
- BM_IsSelected(BM_Entry* entry)
- {
- return BM_ISSELECTED(entry);
- }
-
-
- int32
- BM_GetChangedState(BM_Entry* entry)
- {
- if (BM_ISALIAS(entry)) {
- entry = entry->d.alias.original;
- }
- if (BM_ISURL(entry)) {
- if (entry->d.url.last_modified == 0 || entry->flags & BM_ATTR_CHECKING) {
- return BM_CHANGED_UNKNOWN;
- }
- if (entry->d.url.last_visit < entry->d.url.last_modified) {
- return BM_CHANGED_YES;
- }
- }
- return BM_CHANGED_NO;
- }
-
- /* globals */
- static MWContext* ContextList = NULL;
-
-
- void
- BM_SetFEData(MWContext* context, void* data)
- {
- BM_Frame* f = GETFRAME(context);
- CHKCONTEXTVOID(context);
- f->feData = data;
- }
-
- void*
- BM_GetFEData(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- CHKCONTEXT(context);
- return f->feData;
- }
-
-
- /* creates a new empty bookmark entry */
- static BM_Entry*
- bm_NewEntry(int16 type)
- {
- BM_Entry* new_entry = XP_NEW_ZAP(BM_Entry);
- if (!new_entry) return NULL;
- XP_MEMSET(new_entry, 0, sizeof(BM_Entry));
- new_entry->type = type;
- return new_entry;
- }
-
- /* creates a new header bookmarks entry */
- BM_Entry*
- BM_NewHeader(const char* name)
- {
- BM_Entry* header;
- header = bm_NewEntry(BM_TYPE_HEADER);
- if (!header) return NULL;
- StrAllocCopy(header->name, name);
- return header;
- }
-
- /* creates a new URL bookmarks entry */
- BM_Entry*
- BM_NewUrl(const char* name, const char* address, const char* content_type,
- BM_Date last_visit)
- {
- BM_Entry* url;
-
- url = bm_NewEntry(BM_TYPE_URL);
-
- if (!url) return NULL;
-
- StrAllocCopy(url->name, name);
- url->description = NULL;
- StrAllocCopy(url->d.url.address, address);
- StrAllocCopy(url->d.url.content_type, content_type);
- url->d.url.last_visit = last_visit;
- url->d.url.last_modified = last_visit; /* ### Is this right? */
- url->addition_date = 0;
-
- return url;
- }
-
- /* creates a new URL bookmarks entry */
- static BM_Entry*
- bm_NewAddress(const char* name, const char* address)
- {
- BM_Entry* add_struct;
-
- add_struct = bm_NewEntry(BM_TYPE_ADDRESS);
-
- if (!add_struct) return NULL;
-
- StrAllocCopy(add_struct->name, name ? name : "");
- StrAllocCopy(add_struct->d.address.address, address ? address : "");
-
- return add_struct;
- }
-
- /* creates a new separator bookmarks entry */
- static BM_Entry*
- bm_NewSeparator(void)
- {
- return bm_NewEntry(BM_TYPE_SEPARATOR);
- }
-
- /* creates a new alias bookmarks entry */
- static BM_Entry*
- bm_NewAlias(BM_Entry* original)
- {
- BM_Entry* alias;
- alias = bm_NewEntry(BM_TYPE_ALIAS);
- alias->d.alias.original = original;
- BM_SETFLAG(original, BM_ATTR_HASALIASES);
- return alias;
- }
-
- extern BM_Entry* BM_CopyBookmark(MWContext* context, BM_Entry* original)
- {
- BM_Entry* copy;
- BM_Entry* child;
- BM_Entry* childCopy;
-
- copy = NULL;
-
- if(!original)
- return NULL;
-
- switch (original->type) {
- case BM_TYPE_URL:
- copy = BM_NewUrl(original->name, original->d.url.address,
- original->d.url.content_type, original->d.url.last_visit);
- break;
- case BM_TYPE_ADDRESS:
- copy = bm_NewAddress(original->name, original->d.address.address);
- break;
- case BM_TYPE_SEPARATOR:
- copy = bm_NewSeparator();
- break;
- case BM_TYPE_ALIAS:
- copy = bm_NewAlias(original->d.alias.original);
- break;
- case BM_TYPE_HEADER:
- copy = BM_NewHeader(original->name);
-
- child = original->d.header.children;
-
- while (child) {
- childCopy = BM_CopyBookmark(context, child);
- if(childCopy)
- BM_AppendToHeader(context, copy, childCopy);
- child = child->next;
- }
- break;
- }
-
- if(copy)
- {
- StrAllocCopy(copy->description, original->description);
- StrAllocCopy(copy->nickname, original->nickname);
- }
- return copy;
- }
-
- /* gets the top node of the bmlist */
- BM_Entry*
- BM_GetRoot(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- CHKCONTEXT(context);
- if (!f) return NULL;
- if (!f->gBookmarks) {
- f->gBookmarks = BM_NewHeader(context->type == MWContextBookmarks ?
- XP_GetString(XP_BKMKS_HEADER) : XP_GetString(XP_ADDRBOOK_HEADER));
- if (context->type == MWContextBookmarks) {
- f->menuheader = f->addheader = f->gBookmarks;
- }
- bm_SyncCount(context);
- } else {
- if (f->gBookmarks->parent != NULL)
- XP_ASSERT(f->gBookmarks->next == NULL); /* Stupid consistancy test;
- dunno what action to take if
- this isn't so. */
- }
- return f->gBookmarks;
- }
-
- static void
- bm_EachEntryDo_1(MWContext* context, BM_Entry* at, EntryFunc func, void* closure)
- {
- BM_Entry* nextChild;
- BM_Entry* children;
-
- while (at) {
- nextChild = at->next;
- if (BM_ISHEADER(at)) {
- children = at->d.header.children;
- } else {
- children = NULL;
- }
-
- (*func)(context, at, closure);
-
- if (children) {
- bm_EachEntryDo_1(context, children, func, closure);
- }
-
- at = nextChild;
- }
- }
-
- static void
- bm_EachSelectedEntryDo_1(MWContext* context, BM_Entry* at, EntryFunc func,
- void* closure)
- {
- BM_Entry* nextChild;
- BM_Entry* children;
-
- while (at) {
- nextChild = at->next;
- if (BM_ISHEADER(at)) {
- children = at->d.header.children;
- } else {
- children = NULL;
- }
-
- if (BM_ISSELECTED(at)) (*func)(context, at, closure);
-
- if (children) {
- bm_EachSelectedEntryDo_1(context, children, func, closure);
- }
-
- at = nextChild;
- }
- }
-
- static void
- bm_EachProperSelectedEntryDo_1(MWContext* context, BM_Entry* at, EntryFunc func,
- void* closure, struct BM_Entry_Focus* bmFocus)
- {
- BM_Entry* child;
- BM_Entry* nextChild;
-
- XP_ASSERT(at);
- if (!at) return;
-
- XP_ASSERT(BM_ISHEADER(at));
- child = at->d.header.children;
-
- while (child) {
- nextChild = child->next;
- switch (child->type) {
- case BM_TYPE_URL:
- case BM_TYPE_ADDRESS:
- case BM_TYPE_SEPARATOR:
- case BM_TYPE_ALIAS:
- if (BM_ISSELECTED(child)) {
- if ((bmFocus != NULL) && !bmFocus->foundSelection)
- bmFocus->foundSelection = TRUE;
- (*func)(context, child, closure);
- }
- else if (bmFocus && !bmFocus->foundSelection) {
- bmFocus->saveFocus = child;
- }
- break;
- case BM_TYPE_HEADER:
- if (BM_ISSELECTED(child)) {
- if ((bmFocus != NULL) && !bmFocus->foundSelection)
- bmFocus->foundSelection = TRUE;
- (*func)(context, child, closure);
- }
- else {
- if (bmFocus && !bmFocus->foundSelection)
- bmFocus->saveFocus = child;
- if (! BM_ISFOLDED(child)) {
- bm_EachProperSelectedEntryDo_1(context, child, func, closure, bmFocus);
- }
- }
- break;
- }
- child = nextChild;
- }
- }
-
-
-
- void
- BM_EachEntryDo(MWContext* context, EntryFunc func, void* closure)
- {
- CHKCONTEXTVOID(context);
- bm_EachEntryDo_1(context, BM_GetRoot(context), func, closure);
- }
-
- void
- BM_EachSelectedEntryDo(MWContext* context, EntryFunc func, void* closure)
- {
- CHKCONTEXTVOID(context);
- bm_EachSelectedEntryDo_1(context, BM_GetRoot(context), func, closure);
- }
-
- void
- BM_EachProperSelectedEntryDo(MWContext* context, EntryFunc func, void* closure,
- struct BM_Entry_Focus* bmFocus)
- {
- CHKCONTEXTVOID(context);
- bm_EachProperSelectedEntryDo_1(context, BM_GetRoot(context), func, closure,
- bmFocus);
- }
-
-
-
- static void
- bm_ClearMarkEverywhere_1(MWContext* context, BM_Entry* entry, void* closure)
- {
- BM_CLEARFLAG(entry, BM_ATTR_MARKED);
- }
-
-
- static void
- bm_ClearMarkEverywhere(MWContext* context)
- {
- BM_EachEntryDo(context, bm_ClearMarkEverywhere_1, NULL);
- }
-
-
- static MWContext*
- bm_GetContextForEntry(BM_Entry* entry)
- {
- MWContext* result;
- BM_Frame* f;
- while (entry->parent) entry = entry->parent;
- for (result = ContextList ; result ; result = f->next) {
- f = GETFRAME(result);
- if (f->gBookmarks == entry) return result;
- }
- return NULL;
- }
-
-
- BM_Type
- BM_GetType(BM_Entry* entry)
- {
- XP_ASSERT(entry);
- return entry ? entry->type : 0;
- }
-
-
- /* return the "name" for item -- may vary depending on its type */
- char*
- BM_GetName(BM_Entry* entry)
- {
- XP_ASSERT(entry);
- if (!entry) return NULL;
-
- switch (entry->type) {
- case BM_TYPE_URL:
- case BM_TYPE_HEADER:
- case BM_TYPE_ADDRESS:
- return entry->name;
- case BM_TYPE_ALIAS:
- if (entry->d.alias.original)
- return BM_GetName(entry->d.alias.original);
- else
- return entry->name;
- default:
- return NULL;
- }
- }
-
- /* return the "address" for item -- may vary depending
- on its type */
- char*
- BM_GetAddress(BM_Entry* entry)
- {
- XP_ASSERT(entry);
- if (!entry) return NULL;
-
- switch (entry->type) {
- case BM_TYPE_URL:
- return entry->d.url.address;
- case BM_TYPE_ADDRESS:
- return entry->d.address.address;
- case BM_TYPE_HEADER:
- case BM_TYPE_SEPARATOR:
- case BM_TYPE_ALIAS:
- if (entry->d.alias.original) return BM_GetAddress(entry->d.alias.original);
- return NULL;
- default:
- return NULL;
- }
- }
-
- /* return the "target" for item -- may vary depending
- on its type */
- char*
- BM_GetTarget(BM_Entry* entry, XP_Bool recurse)
- {
- XP_ASSERT(entry);
- if (!entry) return NULL;
-
- switch (entry->type) {
- case BM_TYPE_URL:
- if ((recurse)&&(entry->d.url.target == NULL)&&(entry->parent != NULL))
- {
- return BM_GetTarget(entry->parent, recurse);
- }
- else
- {
- return entry->d.url.target;
- }
- case BM_TYPE_HEADER:
- if ((recurse)&&(entry->d.header.target == NULL)&&(entry->parent != NULL))
- {
- return BM_GetTarget(entry->parent, recurse);
- }
- else
- {
- return entry->d.header.target;
- }
- case BM_TYPE_ADDRESS:
- case BM_TYPE_SEPARATOR:
- return NULL;
- case BM_TYPE_ALIAS:
- if (entry->d.alias.original) return BM_GetTarget(entry->d.alias.original, recurse);
- return NULL;
- default:
- return NULL;
- }
- }
-
- /* return the "description" for item -- may vary depending on its type */
- char*
- BM_GetDescription(BM_Entry* entry)
- {
- XP_ASSERT(entry);
- if (!entry) return NULL;
-
- switch (entry->type) {
- case BM_TYPE_URL:
- case BM_TYPE_HEADER:
- case BM_TYPE_ADDRESS:
- return entry->description;
- default:
- return NULL;
- }
- }
-
- char*
- BM_GetNickName(BM_Entry* entry)
- {
- XP_ASSERT(bm_GetContextForEntry(entry)->type == MWContextAddressBook);
- if (BM_ISALIAS(entry)) return BM_GetNickName(entry->d.alias.original);
- else return entry->nickname;
- }
-
-
- PRIVATE int32
- bm_CountAliases_1(BM_Entry* at, BM_Entry* forEntry)
- {
- int32 count = 0;
- for ( ; at ; at = at->next) {
- if (BM_ISHEADER(at)) {
- count += bm_CountAliases_1(at->d.header.children, forEntry);
- } else if (BM_ISALIAS(at)) {
- if (at->d.alias.original == forEntry) count++;
- }
- }
- return count;
- }
-
- PUBLIC int32
- BM_CountAliases(MWContext* context, BM_Entry* entry)
- {
- int32 result;
- CHKCONTEXT(context);
- result = bm_CountAliases_1(BM_GetRoot(context), entry);
- if (result) {
- XP_ASSERT(entry->flags & BM_ATTR_HASALIASES);
- BM_SETFLAG(entry, BM_ATTR_HASALIASES);
- } else {
- BM_CLEARFLAG(entry, BM_ATTR_HASALIASES);
- }
- return result;
- }
-
- BM_Date
- BM_GetLastVisited(BM_Entry *entry)
- {
- XP_ASSERT(entry);
- if (!entry || (entry->type != BM_TYPE_URL)) return 0;
-
- return entry->d.url.last_visit;
- }
-
- BM_Date
- BM_GetAdditionDate(BM_Entry *entry)
- {
- XP_ASSERT(entry);
-
- if (!entry) return 0;
-
- return entry->addition_date;
- }
-
-
- /* pretty print the last visited date ### fix i18n */
- char*
- BM_PrettyLastVisitedDate(BM_Entry* entry)
- {
- static char buffer[200];
-
- buffer[0] = 0;
-
- XP_ASSERT(entry);
- if (!entry) return NULL;
-
- if (entry->type == BM_TYPE_URL) {
- time_t lastVisited;
- time_t today;
- time_t elapsed;
-
- lastVisited = entry->d.url.last_visit;
- if (lastVisited == 0) return "";
- today = XP_TIME();
-
- elapsed = today - lastVisited;
-
- if (elapsed < SECONDS_PER_DAY) {
- int32 hours = (elapsed + 1800L) / 3600L;
- if (hours < 1) {
- return XP_GetString(XP_BKMKS_LESS_THAN_ONE_HOUR_AGO);
- }
- sprintf(buffer, XP_GetString(XP_BKMKS_HOURS_AGO), hours);
- } else if (elapsed < (SECONDS_PER_DAY * 31)) {
- sprintf(buffer, XP_GetString(XP_BKMKS_DAYS_AGO),
- (elapsed + (SECONDS_PER_DAY / 2)) / SECONDS_PER_DAY);
- } else {
- struct tm* tmp;
- tmp = localtime(&lastVisited);
-
- sprintf(buffer, asctime(tmp));
- }
- return buffer;
- }
- return NULL;
- }
-
- /* pretty print the added on date */
- char*
- BM_PrettyAddedOnDate(BM_Entry* entry)
- {
- static char buffer[200];
- struct tm* tmp;
-
- XP_ASSERT(entry);
-
- if (entry && entry->addition_date != 0) {
- tmp = localtime(&(entry->addition_date));
- sprintf(buffer, asctime(tmp));
- return buffer;
- }
- return NULL;
- }
-
- char*
- BM_PrettyAliasCount(MWContext* context, BM_Entry* entry)
- {
- static char buffer[100];
- int32 count;
- char* name = context->type == MWContextBookmarks ?
- XP_GetString(XP_BKMKS_BOOKMARK) : XP_GetString(XP_BKMKS_ENTRY);
- CHKCONTEXT(context);
- XP_ASSERT(entry);
- if (!entry) return NULL;
-
- count = BM_CountAliases(context, entry);
- buffer[0] = 0;
-
- if (count > 1) {
- sprintf(buffer, XP_GetString(XP_BKMKS_COUNTALIASES_MANY), count, name);
- } else if (count == 1) {
- sprintf(buffer, XP_GetString(XP_BKMKS_COUNTALIASES_ONE), name);
- } else {
- sprintf(buffer, XP_GetString(XP_BKMKS_COUNTALIASES_NONE), name);
- }
- return buffer;
- }
-
-
- BM_Entry*
- BM_GetChildren(BM_Entry* entry)
- {
- if (BM_ISHEADER(entry)) return entry->d.header.children;
- return NULL;
- }
-
- BM_Entry*
- BM_GetNext(BM_Entry* entry)
- {
- XP_ASSERT(entry);
- return entry ? entry->next : NULL;
- }
-
-
- BM_Entry*
- BM_GetParent(BM_Entry* entry)
- {
- XP_ASSERT(entry);
- return entry ? entry->parent : NULL;
- }
-
-
- XP_Bool
- BM_HasNext(BM_Entry* entry)
- {
- XP_ASSERT(entry);
- return entry ? (entry->next != NULL) : FALSE;
- }
-
-
- XP_Bool
- BM_HasPrev(BM_Entry* entry)
- {
- BM_Entry* parent = entry->parent;
- if (parent) {
- XP_ASSERT(BM_ISHEADER(parent));
- return parent->d.header.children != entry;
- } else {
- return GETFRAME(bm_GetContextForEntry(entry))->gBookmarks != entry;
- }
- }
-
-
- static void
- bm_flush_updates(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- CHKCONTEXTVOID(context);
- if (f->first_update_line > 0) {
- BMFE_RefreshCells(context, f->first_update_line, f->last_update_line,
- FALSE);
- f->first_update_line = 0;
- }
- }
-
- static void
- bm_start_batch(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
-
- #ifdef XP_UNIX
- BMFE_StartBatch(context);
- #endif
-
- CHKCONTEXTVOID(context);
- if (f->undo) UNDO_StartBatch(f->undo);
- f->batch_depth++;
- }
-
- static void
- bm_end_batch(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- CHKCONTEXTVOID(context);
- f->batch_depth--;
- XP_ASSERT(f->batch_depth >= 0);
- if (f->batch_depth == 0) {
- bm_flush_updates(context);
- }
- if (f->undo) UNDO_EndBatch(f->undo, NULL, NULL);
-
- #ifdef XP_UNIX
- BMFE_EndBatch(context);
- #endif
- }
-
- static void
- bm_refresh(MWContext* context, int32 first, int32 last)
- {
- BM_Frame* f = GETFRAME(context);
- CHKCONTEXTVOID(context);
- XP_ASSERT(first >= 1 && first <= last);
- if (first < 1 || first > last) {
- /* Something bogus got passed in; just repaint everything to
- be safe. */
- first = 1;
- last = BM_LAST_CELL;
- }
- if (f->first_update_line <= 0 ||
- first > f->last_update_line + 1 ||
- last + 1 < f->first_update_line) {
- bm_flush_updates(context);
- f->first_update_line = first;
- f->last_update_line = last;
- } else {
- if (f->first_update_line > first) f->first_update_line = first;
- if (f->last_update_line < last) f->last_update_line = last;
- }
- if (f->batch_depth == 0) bm_flush_updates(context);
- }
-
-
- /* Handy routine to detect if we're already going to refresh everything.
- If so, then the caller knows there's no need to refresh any more... */
- static XP_Bool
- bm_refreshing_all(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- return (f != NULL &&
- f->first_update_line == 1 &&
- f->last_update_line == BM_LAST_CELL);
- }
-
-
- static void
- bm_entry_changed_2(MWContext* context, BM_Entry* entry)
- {
- int32 index = BM_GetIndex(context, entry);
- if (index < 1) return;
- if (context->type == MWContextBookmarks || entry->parent == NULL) {
- bm_refresh(context, index, index);
- } else {
- /* Changing the entry might have messed up the sorting order. Better
- go resort it. What a hack...*/
- BM_Entry* parent = entry->parent;
- BM_RemoveChildFromHeader(context, parent, entry);
- bm_AddChildToHeaderSorted(context, parent, entry);
- }
- }
-
- static void
- bm_entry_changed_1(MWContext* context, BM_Entry* entry, BM_Entry* find)
- {
- for (; entry ; entry = entry->next) {
- if (BM_ISALIAS(entry) && entry->d.alias.original == find) {
- bm_entry_changed_2(context, entry);
- } else if (BM_ISHEADER(entry)) {
- bm_entry_changed_1(context, entry->d.header.children, find);
- }
- }
- }
-
- static void
- bm_entry_changed(MWContext* context, BM_Entry* entry)
- {
- XP_ASSERT(!BM_ISALIAS(entry));
- if (entry->flags & BM_ATTR_HASALIASES) {
- bm_entry_changed_1(context, BM_GetRoot(context), entry);
- }
- bm_entry_changed_2(context, entry);
- }
-
-
- static void
- bm_save_timer(void* closure)
- {
- MWContext* context = (MWContext*) closure;
- BM_Frame* f = GETFRAME(context);
- f->savetimer = NULL;
- BM_SaveBookmarks(context, NULL);
- }
-
- /* The bookmarks have been modified somehow. Set or reset a timer to cause
- them to be saved.*/
- static void
- bm_SetModified(MWContext* context, XP_Bool mod)
- {
- BM_Frame* f = GETFRAME(context);
- f->gBookmarksModified = mod;
- f->max_depth = 0;
- if (f->savetimer) {
- FE_ClearTimeout(f->savetimer);
- f->savetimer = NULL;
- }
- if (mod) {
- f->savetimer = FE_SetTimeout(bm_save_timer, context,
- 60000L); /* ### hard-coding... */
- if (!f->savetimer) BM_SaveBookmarks(context, NULL);
- }
- }
-
- /* give LI the ability to set the modified to false */
- void
- BM_SetModified(MWContext* context, XP_Bool mod)
- {
- bm_SetModified(context, mod);
- }
-
- typedef struct bm_setheader_info {
- MWContext* context;
- BM_Entry* entry;
- XP_Bool isadd;
- } bm_setheader_info;
-
- static void
- bm_setheader_freeit(void* closure)
- {
- XP_FREE((bm_setheader_info*) closure);
- }
-
- static int bm_setheader_undo(void* closure);
-
- static void
- bm_SetMenuOrAddHeader(MWContext* context, BM_Entry* entry, XP_Bool isadd)
- {
- BM_Frame* f = GETFRAME(context);
- XP_ASSERT(context->type == MWContextBookmarks);
- XP_ASSERT(BM_ISHEADER(entry));
- if (context->type == MWContextBookmarks && f && BM_ISHEADER(entry)) {
- if (f->undo) {
- bm_setheader_info* info = XP_NEW_ZAP(bm_setheader_info);
- if (!info) {
- UNDO_DiscardAll(f->undo);
- } else {
- info->context = context;
- info->entry = isadd ? f->addheader : f->menuheader;
- info->isadd = isadd;
- UNDO_LogEvent(f->undo, bm_setheader_undo, bm_setheader_freeit, info, NULL, NULL);
- }
- }
- bm_start_batch(context);
- bm_entry_changed(context, isadd ? f->addheader : f->menuheader);
- if (isadd) f->addheader = entry;
- else f->menuheader = entry;
- bm_entry_changed(context, entry);
- if (!isadd) BMFE_BookmarkMenuInvalid(context);
- bm_SetModified(context, TRUE);
- bm_end_batch(context);
- }
- }
-
- int bm_setheader_undo(void* closure)
- {
- bm_setheader_info* info = (bm_setheader_info*) closure;
- bm_SetMenuOrAddHeader(info->context, info->entry, info->isadd);
- return 0;
- }
-
- BM_Entry*
- BM_GetMenuHeader(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- XP_ASSERT(context->type == MWContextBookmarks);
- return f ? f->menuheader : NULL;
- }
-
- void BM_SetMenuHeader(MWContext* context, BM_Entry* entry)
- {
- bm_SetMenuOrAddHeader(context, entry, FALSE);
- }
-
-
- BM_Entry*
- BM_GetAddHeader(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- XP_ASSERT(context->type == MWContextBookmarks);
- return f ? f->addheader : NULL;
- }
-
- void BM_SetAddHeader(MWContext* context, BM_Entry* entry)
- {
- bm_SetMenuOrAddHeader(context, entry, TRUE);
- }
-
-
- typedef struct bm_copy_string_info {
- MWContext* context;
- BM_Entry* entry;
- char** string;
- char* value;
- } bm_copy_string_info;
-
-
- static void
- bm_copy_string_freeit(void* closure)
- {
- bm_copy_string_info* info = (bm_copy_string_info*) closure;
- FREEIF(info->value);
- XP_FREE(info);
- }
-
- static int bm_copy_string_undo(void* closure);
-
- static int
- bm_CopyStringWithUndo(MWContext* context, BM_Entry* entry, char** string,
- const char* value)
- {
- BM_Frame* f = GETFRAME(context);
- int status = 0;
- bm_SetModified(context, TRUE);
- if (f->undo) {
- bm_copy_string_info* info = XP_NEW_ZAP(bm_copy_string_info);
- if (!info) {
- UNDO_DiscardAll(f->undo);
- status = MK_OUT_OF_MEMORY;
- } else {
- info->context = context;
- info->entry = entry;
- info->string = string;
- info->value = *string ? XP_STRDUP(*string) : NULL;
- UNDO_LogEvent(f->undo, bm_copy_string_undo, bm_copy_string_freeit,
- info, NULL, NULL);
- }
- }
- if (*string) XP_FREE(*string);
- *string = value ? XP_STRDUP(value) : NULL;
- bm_entry_changed(context, entry);
- return 0;
- }
-
- static int
- bm_copy_string_undo(void* closure)
- {
- bm_copy_string_info* info = (bm_copy_string_info*) closure;
- if (info->string == &(info->entry->nickname)) {
- /* Have to use BM_SetNickName to get side effect of changing hashtable. */
- BM_SetNickName(info->context, info->entry, info->value);
- } else {
- bm_CopyStringWithUndo(info->context, info->entry, info->string,
- info->value);
- }
- return 0;
- }
-
-
-
- /* sets the name for a bm entry */
- void
- BM_SetName(MWContext* context, BM_Entry* entry, const char* newName)
- {
- CHKCONTEXTVOID(context);
- XP_ASSERT(entry);
- if (!entry) return;
- BM_CLEARFLAG(entry, BM_ATTR_ISNEW);
-
- switch (entry->type) {
- case BM_TYPE_URL:
- case BM_TYPE_HEADER:
- case BM_TYPE_ADDRESS:
- if (entry->name == NULL || XP_STRCMP(entry->name, newName) != 0) {
- bm_CopyStringWithUndo(context, entry, &entry->name, newName);
- BMFE_BookmarkMenuInvalid(context);
- }
- break;
- case BM_TYPE_ALIAS:
- BM_SetName(context, entry->d.alias.original, newName);
- break;
- }
- }
-
-
-
- /* sets the location field of a bm_url bookmarks entry */
- void
- BM_SetAddress(MWContext* context, BM_Entry* entry, const char* newAddress)
- {
- CHKCONTEXTVOID(context);
- XP_ASSERT(entry);
- if (!entry) return;
- BM_CLEARFLAG(entry, BM_ATTR_ISNEW);
-
- switch (entry->type) {
- case BM_TYPE_URL:
- if (entry->d.url.address == NULL ||
- XP_STRCMP(entry->d.url.address, newAddress) != 0) {
- bm_CopyStringWithUndo(context, entry, &entry->d.url.address, newAddress);
- }
- break;
- case BM_TYPE_ADDRESS:
- if (entry->d.address.address == NULL ||
- XP_STRCMP(entry->d.address.address, newAddress) != 0) {
- bm_CopyStringWithUndo(context, entry, &entry->d.address.address,
- newAddress);
- }
- break;
- case BM_TYPE_ALIAS:
- BM_SetAddress(context, entry->d.alias.original, newAddress);
- break;
- }
- }
-
-
- /* sets the target field of a bm_url bookmarks entry */
- void
- BM_SetTarget(MWContext* context, BM_Entry* entry, const char* newTarget)
- {
- CHKCONTEXTVOID(context);
- XP_ASSERT(entry);
- if (!entry) return;
- BM_CLEARFLAG(entry, BM_ATTR_ISNEW);
-
- switch (entry->type) {
- case BM_TYPE_URL:
- if (entry->d.url.target == NULL ||
- XP_STRCMP(entry->d.url.target, newTarget) != 0) {
- bm_CopyStringWithUndo(context, entry, &entry->d.url.target, newTarget);
- if (entry->d.url.target[0] == '\0') {
- entry->d.url.target = NULL;
- }
- }
- break;
- case BM_TYPE_HEADER:
- if (entry->d.header.target == NULL ||
- XP_STRCMP(entry->d.header.target, newTarget) != 0) {
- bm_CopyStringWithUndo(context, entry, &entry->d.header.target, newTarget);
- if (entry->d.header.target[0] == '\0') {
- entry->d.header.target = NULL;
- }
- }
- break;
- case BM_TYPE_ADDRESS:
- break;
- case BM_TYPE_ALIAS:
- BM_SetAddress(context, entry->d.alias.original, newTarget);
- break;
- }
- }
-
- /* sets the description field of an entry */
- PUBLIC void
- BM_SetDescription(MWContext* context, BM_Entry* entry, const char* newDesc)
- {
- CHKCONTEXTVOID(context);
- XP_ASSERT(entry);
- if (!entry) return;
- BM_CLEARFLAG(entry, BM_ATTR_ISNEW);
-
- switch (entry->type) {
- case BM_TYPE_URL:
- case BM_TYPE_HEADER:
- case BM_TYPE_ADDRESS:
- if (entry->description == NULL ||
- XP_STRCMP(entry->description, newDesc)) {
- bm_CopyStringWithUndo(context, entry, &entry->description, newDesc);
- }
- break;
- case BM_TYPE_ALIAS:
- BM_SetDescription(context, entry->d.alias.original, newDesc);
- break;
- }
- }
-
-
- /* BM_SetNickName returns FALSE if it reported an error to the user .
- * It returns TRUE if everything worked fine.
- * 5-16-95 jefft
- * Passing in NULL value removes the entry from the hash table.
- */
-
- XP_Bool
- BM_SetNickName(MWContext* context, BM_Entry* entry, const char* value)
- {
- BM_Frame* f = GETFRAME(context);
- char* pName;
- CHKCONTEXT(context);
- XP_ASSERT(context->type == MWContextAddressBook);
- if (!entry) return(TRUE);
- if (!value) {
- /* 5-16-95 jefft -- bug#: 20808, remove entry from the hash table */
- if (entry->nickname && *entry->nickname) {
- XP_Remhash(f->nicknameTable, entry->nickname);
- FREEIF(entry->nickname);
- }
- return(TRUE);
- }
-
- /* allocate a copy of the string so we can modify it to be a legal alias */
- /* But only if value is non-null */
- pName = (value) ? XP_STRDUP(value) : NULL;
- if (value && !pName) return(FALSE);
-
- BM_CLEARFLAG(entry, BM_ATTR_ISNEW);
-
- if (BM_ISALIAS(entry)) {
- XP_Bool retVal;
- retVal = BM_SetNickName(context, entry->d.alias.original, value);
- XP_FREE(pName);
- return(retVal);
- } else {
- if (entry->nickname == NULL || value == NULL || XP_STRCMP(entry->nickname, value)) {
- if (pName != NULL)
- {
- char* ptr;
- for (ptr = pName ; *ptr ; ptr++) {
- if (!isalnum(*ptr) && (*ptr != '-') && (*ptr != '_')) {
- FE_Alert(context, XP_GetString(XP_BKMKS_INVALID_NICKNAME));
- XP_FREE(pName);
- return(FALSE);
- }
- /* convert to lowercase */
- if (isupper(*ptr)) {
- *ptr = (char)tolower(*ptr);
- }
- }
- if (XP_Gethash(f->nicknameTable, pName, NULL)) {
- FE_Alert(context, XP_GetString(XP_BKMKS_NICKNAME_ALREADY_EXISTS));
- FREEIF(pName);
- return(FALSE);
- }
- }
- }
- if (entry->nickname && *entry->nickname) {
- XP_Remhash(f->nicknameTable, entry->nickname);
- }
- bm_CopyStringWithUndo(context, entry, &entry->nickname, pName);
- if (entry->nickname && *entry->nickname) {
- XP_Puthash(f->nicknameTable, entry->nickname, entry);
- }
- }
- FREEIF(pName);
- return(TRUE);
- }
-
-
-
- void
- BM_CancelEdit(MWContext* context, BM_Entry* entry)
- {
- CHKCONTEXTVOID(context);
- bm_start_batch(context);
- if (entry && (entry->flags & BM_ATTR_ISNEW) &&
- !(entry->flags & BM_ATTR_HASALIASES) && entry->parent) {
- BM_RemoveChildFromHeader(context, entry->parent, entry);
- BM_FreeEntry(context, entry);
- bm_refresh(context, 1, BM_LAST_CELL);
- }
- bm_end_batch(context);
- }
-
-
-
- /* returns the number of children parent has
- if visible is TRUE, only visible children are counted,
- otherwise all children are counted */
- static int32
- bm_CountChildren(BM_Entry* parent, XP_Bool visible)
- {
- BM_Entry* child;
- int32 count = 1;
-
- XP_ASSERT(parent);
- XP_ASSERT(BM_ISHEADER(parent));
-
- if (!parent || !BM_ISHEADER(parent)) return 0;
-
- if (!visible || !(parent->flags & BM_ATTR_FOLDED)) {
- child = parent->d.header.children;
- while (child) {
- if (BM_ISHEADER(child)) {
- count += bm_CountChildren(child, visible);
- } else {
- count++;
- }
- child = child->next;
- }
- }
-
- return count;
- }
-
-
- static void
- bm_WidestEntry_1(MWContext* context, BM_Entry* parent, BM_Entry** widest,
- uint32* widestWidth)
- {
- BM_Entry* child;
- uint32 width;
- uint32 height;
-
- XP_ASSERT(parent);
- XP_ASSERT(BM_ISHEADER(parent));
- XP_ASSERT(widestWidth);
- XP_ASSERT(widest);
-
- BMFE_MeasureEntry(context, parent, &width, &height);
-
- if (width > *widestWidth) {
- *widestWidth = width;
- *widest = parent;
- }
-
- if (!(BM_ISFOLDED(parent))) {
- child = parent->d.header.children;
- while (child) {
- if (BM_ISHEADER(child)) {
- bm_WidestEntry_1(context, child, widest, widestWidth);
- } else {
- BMFE_MeasureEntry(context, child, &width, &height);
- if (width > *widestWidth) {
- *widestWidth = width;
- *widest = child;
- }
- }
- child = child->next;
- }
- }
- }
-
- /* returns the widest visible entry in the tree
- (this uses a FE function to measure the width) */
- PUBLIC BM_Entry*
- BM_WidestEntry(MWContext* context)
- {
- BM_Entry* widest = NULL;
- uint32 widestWidth = 0;
- CHKCONTEXT(context);
-
- bm_WidestEntry_1(context, BM_GetRoot(context), &widest, &widestWidth);
- return widest;
- }
-
-
- static void
- bm_SyncCount(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- if (f) {
- f->gCount = -1;
- f->gVisCount = -1;
- }
- BMFE_SyncDisplay(context);
- }
-
- PRIVATE void
- bm_SyncSelection_1(BM_Entry* parent, int32* count, uint32* selectionMask)
- {
- BM_Entry* child;
-
- XP_ASSERT(parent);
- XP_ASSERT(BM_ISHEADER(parent));
-
- if (parent->flags & BM_ATTR_SELECTED) {
- *selectionMask |= BM_TYPE_HEADER;
- (*count)++;
- }
-
- child = parent->d.header.children;
- while (child) {
- if (BM_ISHEADER(child)) {
- bm_SyncSelection_1(child, count, selectionMask);
- } else {
- if (BM_ISSELECTED(child)) {
- *selectionMask |= child->type;
- (*count)++;
- }
- }
- child = child->next;
- }
- }
-
- /* synchronizes the selection mask and the selection count with
- what is actually selected
- this is necessary when items become deselected because
- we don't have a global selection list, only a count and
- mask
- */
- static void
- bm_SyncSelection(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- f->gSelectionCount = 0;
- f->gSelectionMask = 0;
-
- bm_SyncSelection_1(BM_GetRoot(context), &(f->gSelectionCount),
- &(f->gSelectionMask));
- }
-
- /* return the index number of item in cur_count with regards
- to the BM_ATTR_FOLDED flag */
- PRIVATE int32
- bm_GetIndexNum(BM_Entry* parent, BM_Entry* item, int32* cur_count)
- {
- BM_Entry* child;
- int32 rv = 0;
-
- XP_ASSERT(parent);
- XP_ASSERT(BM_ISHEADER(parent));
-
- child = parent->d.header.children;
-
- if (parent == item) return *cur_count;
-
- while (child) {
- (*cur_count)++;
-
- if (child == item) {
- return *cur_count;
- }
-
- /* if it's a header and it's unfolded, traverse it's children */
- if (child->type == BM_TYPE_HEADER && !BM_ISFOLDED(child)) {
- rv = bm_GetIndexNum(child, item, cur_count);
- if (rv)
- return rv;
- }
- child = child->next;
- }
- return 0;
- }
-
- /* return the index number of item in cur_count without regards to
- the BM_ATTR_FOLDED flag */
- PRIVATE int32
- bm_GetUnfoldedIndexNum(BM_Entry* parent, BM_Entry* item, int32* cur_count)
- {
- BM_Entry* child;
- int32 rv = 0;
-
- XP_ASSERT(parent);
- XP_ASSERT(parent->type == BM_TYPE_HEADER);
-
- if (parent == item) return *cur_count;
-
- for (child = parent->d.header.children; child; child = child->next) {
- (*cur_count)++;
-
- if (child == item) return *cur_count;
-
-
- if (child->type == BM_TYPE_HEADER) {
- rv = bm_GetUnfoldedIndexNum(child, item, cur_count);
- if (rv) return rv;
- }
- }
- return 0;
- }
-
- /* returns the child url entry of parent whose address is the same as
- url_address */
- PRIVATE void
- bm_FindItemStub(MWContext *context, BM_Entry* parent, char* url_address, EntryFunc pf, void *pClosure)
- {
- BM_Entry* child;
-
- if (!parent) { /* Eric made me do it */
- return;
- }
-
- for (child = parent->d.header.children; child; child = child->next) {
- if (child->type == BM_TYPE_URL && child->d.url.address &&
- !XP_STRCMP(child->d.url.address, url_address)) {
- (*pf)(context, child, pClosure);
- }
- if (child->type == BM_TYPE_HEADER) {
- bm_FindItemStub(context, child, url_address, pf, pClosure);
- }
- }
- return;
- }
-
-
- PRIVATE int32
- bm_GetDepth(BM_Entry* parent, BM_Entry* item)
- {
- int32 rv = 0;
- BM_Entry* next;
-
- if (!item) return -1;
-
- next = item;
- while (next && next->parent) { /* I think extra "next &&" is
- necessary for Win16 busted
- optimizer... */
- rv++;
- next = next->parent;
- }
- return rv;
- }
-
-
-
- static void
- bm_simple_freeit(void* closure)
- {
- XP_FREE(closure);
- }
-
-
- typedef struct bm_delete_child_info {
- MWContext* context;
- BM_Entry* parent;
- BM_Entry* child;
- } bm_delete_child_info;
-
-
- static int
- bm_delete_child_doit(void* closure)
- {
- bm_delete_child_info* info = (bm_delete_child_info*) closure;
- BM_RemoveChildFromHeader(info->context, info->parent, info->child);
- return 0;
- }
-
-
- static void
- bm_LogDeleteChild(MWContext* context, BM_Entry* parent, BM_Entry* child)
- {
- BM_Frame* f = GETFRAME(context);
- bm_delete_child_info* info;
-
- /* Magic side effect -- if a child has just been added, and it doesn't have
- an addition date set, set it to be now. */
- if (child->addition_date == 0) {
- child->addition_date = XP_TIME();
- }
-
- if (!f || !f->undo) return;
- bm_SetModified(context, TRUE);
- info = XP_NEW_ZAP(bm_delete_child_info);
- if (!info) {
- UNDO_DiscardAll(f->undo);
- } else {
- info->context = context;
- info->parent = parent;
- info->child = child;
- UNDO_LogEvent(f->undo, bm_delete_child_doit, bm_simple_freeit, info, NULL, NULL);
- }
- }
-
- /* appends a child item to a parent at the end of the
- parents child list */
- static void
- bm_AppendChildToHeader(MWContext* context, BM_Entry* parent, BM_Entry* child)
- {
- BM_Frame* f = GETFRAME(context);
- BM_Entry* lastChild;
-
- XP_ASSERT(parent);
- XP_ASSERT(BM_ISHEADER(parent));
- XP_ASSERT(child);
- XP_ASSERT(child != parent);
-
- f->gCount = -1;
- f->gVisCount = -1;
-
- lastChild = parent->d.header.lastChild;
- if (lastChild) {
- lastChild->next = child;
- parent->d.header.lastChild = child;
- } else {
- parent->d.header.children = child;
- parent->d.header.lastChild = child;
- }
-
- parent->d.header.childCount++;
- child->parent = parent;
-
- if( !f->bSorting )
- child->iNaturalIndex = g_iNaturalIndexPool++;
-
- if (context) {
- BMFE_BookmarkMenuInvalid(context);
- bm_LogDeleteChild(context, parent, child);
- }
- }
-
- void
- BM_AppendToHeader(MWContext* context, BM_Entry* parent, BM_Entry* child)
- {
- int index;
- bm_start_batch(context);
- bm_AppendChildToHeader(context, parent, child);
- index = BM_GetIndex(context, child);
- if (index > 0) bm_refresh(context, index, BM_LAST_CELL);
- bm_end_batch(context);
- }
-
-
- /* Add a child item to a parent at the beginning of the
- parents child list */
- void
- BM_PrependChildToHeader(MWContext* context, BM_Entry* parent, BM_Entry* child)
- {
- BM_Frame* f = GETFRAME(context);
- BM_Entry* firstChild;
-
- XP_ASSERT(parent);
- XP_ASSERT(parent->type == BM_TYPE_HEADER);
- XP_ASSERT(child);
- XP_ASSERT(child != parent);
-
- f->gCount = -1;
- f->gVisCount = -1;
- firstChild = parent->d.header.children;
- if (!firstChild) {
- bm_AppendChildToHeader(context, parent, child);
- } else {
- child->next = firstChild;
- parent->d.header.children = child;
-
- parent->d.header.childCount++;
- child->parent = parent;
-
- if( !f->bSorting )
- child->iNaturalIndex = g_iNaturalIndexPool++;
-
- if (context) {
- BMFE_BookmarkMenuInvalid(context);
- bm_LogDeleteChild(context, parent, child);
- }
- }
- }
-
-
- static int
- bm_SortAddressBook(const void* obj1, const void* obj2)
- {
- const BM_Entry* entry1 = (const BM_Entry*) obj1;
- const BM_Entry* entry2 = (const BM_Entry*) obj2;
-
- if (BM_ISALIAS(entry1)) {
- entry1 = entry1->d.alias.original;
- XP_ASSERT(!BM_ISALIAS(entry1));
- }
- if (BM_ISALIAS(entry2)) {
- entry2 = entry2->d.alias.original;
- XP_ASSERT(!BM_ISALIAS(entry2));
- }
- XP_ASSERT(BM_ISHEADER(entry1) || BM_ISADDRESS(entry1));
- XP_ASSERT(BM_ISHEADER(entry2) || BM_ISADDRESS(entry2));
- if (entry1 == entry2) return 0; /* Can happen with two aliases to the same
- thing... */
- if (BM_ISHEADER(entry1)) {
- if (BM_ISHEADER(entry2)) {
- #ifdef INTL_SORT
- return XP_StrColl(entry1->name, entry2->name);
- #else
- return XP_STRCMP(entry1->name, entry2->name);
- #endif
- } else {
- return 1;
- }
- } else {
- if (BM_ISHEADER(entry2)) {
- return -1;
- } else {
- #ifdef INTL_SORT
- return XP_StrColl(entry1->name, entry2->name);
- #else
- return XP_STRCMP(entry1->name, entry2->name);
- #endif
- }
- }
- }
-
-
- static BM_Entry*
- bm_RealEntry(BM_Entry* entry)
- {
- if (BM_ISALIAS(entry)) return entry->d.alias.original;
- else return entry;
- }
-
-
- /* Adds a child item to a parent, sorting it according to address book sorting
- rules. */
- static void
- bm_AddChildToHeaderSorted(MWContext* context, BM_Entry* parent,
- BM_Entry* child)
- {
- BM_Frame* f = GETFRAME(context);
- BM_Entry* entry;
- BM_Entry* previous = NULL;
- XP_ASSERT(context->type == MWContextAddressBook);
- XP_ASSERT(BM_ISHEADER(parent));
- if (!BM_ISALIAS(child)) parent = BM_GetRoot(context);
- if (parent->d.header.lastChild &&
- bm_SortAddressBook(parent->d.header.lastChild, child) < 0) {
- /* Ah, the most common case (especially when loading from a file). This
- kid goes last. */
- previous = parent->d.header.lastChild;
- bm_AppendChildToHeader(context, parent, child);
- } else {
- for (entry = parent->d.header.children ; entry ; entry = entry->next) {
- int value = bm_SortAddressBook(entry, child);
- if (value > 0) break;
- if (value == 0) {
- /* Hmm. Let's not allow any duplicate aliases to the same thing
- in the same header. */
- if (bm_RealEntry(entry) == bm_RealEntry(child)) {
- if (BM_ISALIAS(child)) {
- BM_FreeEntry(context, child);
- } else {
- XP_ASSERT(BM_ISALIAS(entry));
- BM_RemoveChildFromHeader(context, parent, entry);
- bm_AddChildToHeaderSorted(context, parent, child);
- }
- return;
- }
- }
- previous = entry;
- }
- if (previous == NULL) {
- BM_PrependChildToHeader(context, parent, child);
- previous = parent;
- } else {
- bm_InsertItemAfter(context, previous, child, FALSE);
- }
- }
- f->gCount = -1;
- f->gVisCount = -1;
- if (!BM_ISFOLDED(parent) && !bm_refreshing_all(context)) {
- int index = BM_GetIndex(context, previous);
- if (index > 0) {
- f->gVisCount++;
- bm_refresh(context, index + 1, BM_LAST_CELL);
- }
- }
- }
-
- static BM_Entry*
- bm_get_previous(BM_Entry* entry)
- {
- BM_Entry* child;
- BM_Entry* previous = NULL;
-
- if (entry && entry->parent) {
- child = entry->parent->d.header.children;
- previous = NULL;
- while (child && child != entry) {
- previous = child;
- child = child->next;
- }
- }
-
- if (child == NULL) previous = NULL;
-
- return previous;
- }
-
-
-
- typedef struct bm_add_child_info {
- MWContext* context;
- BM_Entry* parent;
- BM_Entry* previous;
- BM_Entry* child;
- } bm_add_child_info;
-
-
- static int
- bm_add_child_doit(void* closure)
- {
- bm_add_child_info* info = (bm_add_child_info*) closure;
- XP_ASSERT(info->previous == NULL || info->previous->parent == info->parent);
- if (info->previous) {
- bm_InsertItemAfter(info->context, info->previous, info->child, FALSE);
- } else {
- BM_PrependChildToHeader(info->context, info->parent, info->child);
- }
- BM_ClearAllSelection(info->context, FALSE);
- return 0;
- }
-
-
-
- void BM_RemoveChildFromHeader(MWContext* context, BM_Entry* parent, BM_Entry* child)
- {
- BM_Frame* f = GETFRAME(context);
- BM_Entry* previous;
-
- XP_ASSERT(BM_ISHEADER(parent));
- if (!BM_ISHEADER(parent)) return;
- XP_ASSERT(child);
- if (!child) return;
- XP_ASSERT(child != parent);
- if (child == parent) return;
- XP_ASSERT(child->parent == parent);
- if (child->parent != parent) return;
-
- if (context && (child->flags & BM_ATTR_SELECTED)) {
- BM_SelectItem(context, child, TRUE, TRUE, FALSE);
- }
- previous = bm_get_previous(child);
-
- if (previous) previous->next = child->next;
-
- if (parent->d.header.children == child) {
- parent->d.header.children = child->next;
- }
-
- if (parent->d.header.lastChild == child) {
- parent->d.header.lastChild = previous;
- }
-
- f->gCount = -1;
- f->gVisCount = -1;
-
- parent->d.header.childCount--;
-
- if (context) {
- BM_Frame* f = GETFRAME(context);
- bm_add_child_info* info;
- BMFE_BookmarkMenuInvalid(context);
- bm_SetModified(context, TRUE);
- if (f->undo) {
- info = XP_NEW_ZAP(bm_add_child_info);
- if (!info) {
- UNDO_DiscardAll(f->undo);
- } else {
- info->context = context;
- info->parent = parent;
- info->previous = previous;
- info->child = child;
- UNDO_LogEvent(f->undo, bm_add_child_doit, bm_simple_freeit, info, NULL, NULL);
- }
- }
- }
- child->parent = NULL;
- child->next = NULL;
- }
-
-
-
- #define BM_HEADER_BEGIN 0xD000
- #define BM_HEADER_END 0xE000
- #define BM_UNKNOWN 0xF000
-
- static uint16
- bm_tokenize_line(MWContext* context, char* buffer, char** ptr)
- {
- if ((*ptr = strcasestr(buffer, "HREF=\""))) {
- return context->type == MWContextBookmarks ? BM_TYPE_URL : BM_TYPE_ADDRESS;
- } else if ((*ptr = strcasestr(buffer, "<H")) && isdigit(*(*ptr + 2))) {
- return BM_TYPE_HEADER;
- } else if ((*ptr = strcasestr(buffer, "<HR>"))) {
- return BM_TYPE_SEPARATOR;
- } else if (strcasestr(buffer, "</UL>") ||
- strcasestr(buffer, "</MENU>") ||
- strcasestr(buffer, "</DL>")) {
- return BM_HEADER_END;
- } else if (strcasestr(buffer, "<UL>") ||
- strcasestr(buffer, "<MENU>") ||
- strcasestr(buffer, "<DL>")) {
- return BM_HEADER_BEGIN;
- } else {
- return BM_UNKNOWN;
- }
- }
-
- /* parse out the folded state in buffer */
- static XP_Bool
- bm_is_folded(char* buffer)
- {
- XP_ASSERT(buffer);
- return strcasestr(buffer, "FOLDED") != NULL;
- }
-
- /* parse out the addition date in buffer */
- static time_t
- bm_addition_date(char* buffer)
- {
- char* ptr;
- char* end;
- time_t add_date = 0;
-
- XP_ASSERT(buffer);
-
- ptr = strcasestr(buffer, "ADD_DATE=\"");
- if (ptr)
- {
- /* find the end of the addition date */
- end = XP_STRCHR(ptr + 10, '"');
- if (end)
- {
- /* temporarily stick a NULL in the buffer */
- *end = '\0';
-
- add_date = (time_t)atol(ptr + 10);
-
- /* replace the quote */
- *end = '"';
- }
- }
- return add_date;
- }
-
- /* parse out the last visited or last modified date in buffer */
- static time_t
- bm_last_date(char* buffer, XP_Bool ismodified)
- {
- char* ptr;
- char* start;
- char* end;
- time_t result = 0;
-
- ptr = strcasestr(buffer,
- ismodified ? "LAST_MODIFIED=\"": "LAST_VISIT=\"");
- if (ptr) {
- start = ptr + (ismodified ? 15 : 12);
- end = XP_STRCHR(start, '"');
- if (end) {
- /* temporarily stick a NULL in the buffer */
- *end = '\0';
-
- result = (time_t)atol(start);
-
- /* replace the quote */
- *end = '"';
- }
- }
- return result;
- }
-
-
- /* parse out the target string in buffer */
- static char *
- bm_target(char* buffer, XP_Bool ismodified)
- {
- char* ptr;
- char* start;
- char* end;
- char *result = NULL;
-
- ptr = strcasestr(buffer, "TARGET=\"");
- if (ptr) {
- start = ptr + 8;
- end = XP_STRCHR(start, '"');
- if (end) {
- /* temporarily stick a NULL in the buffer */
- *end = '\0';
-
- result = (start) ? XP_STRDUP(start) : NULL;
-
- /* replace the quote */
- *end = '"';
- }
- }
- return result;
- }
-
-
- typedef struct bm_alias_info {
- char* id; /* String to use for this alias in the file. */
- char* key; /* Key to use to lookup this alias in the table */
- BM_Entry* entry;
- } bm_alias_info;
-
-
- static bm_alias_info*
- bm_find_alias_info(MWContext* context, const char* ptr, XP_Bool create)
- {
- BM_Frame* f = GETFRAME(context);
- bm_alias_info* info = NULL;
- if (f->aliasTable) {
- info = (bm_alias_info *)XP_Gethash(f->aliasTable, ptr, NULL);
- XP_ASSERT(info == NULL || XP_STRCMP(ptr, info->key) == 0);
- if (!info && create) {
- info = XP_NEW_ZAP(bm_alias_info);
- if (info) {
- info->key = XP_STRDUP(ptr);
- XP_Puthash(f->aliasTable, info->key, info);
- }
- }
- }
- return info;
- }
-
- static bm_alias_info*
- bm_find_writealias_info(MWContext* context, BM_Entry* entry)
- {
- BM_Frame* f = GETFRAME(context);
- static char key[20];
- bm_alias_info* info;
- XP_SPRINTF(key, "%ld", (long) entry);
- info = bm_find_alias_info(context, key, TRUE);
- if (info && info->id == NULL) {
- info->id = (char *)XP_ALLOC(10);
- if (info->id) {
- XP_SPRINTF(info->id, "%d", f->aliasID++);
- }
- }
- return info;
- }
-
- static XP_Bool
- bm_free_alias_info(XP_HashTable table, const void* key, void* value,
- void* closure)
- {
- bm_alias_info* info = (bm_alias_info*) value;
- FREEIF(info->id);
- FREEIF(info->key);
- XP_FREE(info);
- return TRUE;
- }
-
-
- static int
- bm_string_cmp (const void *obj1, const void *obj2)
- {
- XP_ASSERT (obj1 && obj2);
- return XP_STRCMP((char*) obj1, (char*) obj2);
- }
-
- static void
- bm_clear_alias_info(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- if (f->aliasTable) {
- XP_Maphash(f->aliasTable, bm_free_alias_info, NULL);
- XP_Clrhash(f->aliasTable);
- } else {
- f->aliasTable = XP_HashTableNew(100, XP_StringHash, bm_string_cmp);
- }
- f->aliasID = 0;
- }
-
-
-
- /* Checks if the given item is an alias to another item, or has aliases to it.
- Takes care of all the required tree mucking, and updating of the alias
- table. The return value is the item for the caller to insert into the
- tree; it is usually but not always the item passed in. */
- static BM_Entry*
- bm_check_read_alias(MWContext* context, BM_Entry* new_item, char* parseString)
- {
- char* ptr;
- char* end = NULL;
- ptr = strcasestr(parseString, "ALIASID=\"");
- if (ptr) {
- ptr += 9;
- end = XP_STRCHR(ptr, '"');
- if (end) {
- bm_alias_info* info;
- *end = '\0';
- info = bm_find_alias_info(context, ptr, TRUE);
- if (info) {
- if (info->entry) {
- /* Sigh. We have the definition of an alias, but there
- have already been some references to this alias, and we don't
- really want to go chasing the references down. Instead, we'll
- just copy our data into the existing record. Yikes. */
- BM_Entry* tmp = XP_NEW(BM_Entry);
- if (tmp) {
- XP_MEMCPY(tmp, info->entry, sizeof(BM_Entry));
- XP_MEMCPY(info->entry, new_item, sizeof(BM_Entry));
- BM_FreeEntry(context, tmp);
- XP_FREE(new_item);
- new_item = info->entry;
- }
- } else {
- info->entry = new_item;
- }
- }
- BM_SETFLAG(new_item, BM_ATTR_HASALIASES);
- }
- } else {
- ptr = strcasestr(parseString, "ALIASOF=\"");
- if (ptr) {
- ptr += 9;
- end = XP_STRCHR(ptr, '"');
- if (end) {
- bm_alias_info* info;
- *end = '\0';
- info = bm_find_alias_info(context, ptr, TRUE);
- if (info) {
- if (info->entry == NULL) {
- /* Even though this entry is probably not complete, it will
- do better than nothing. If something better comes along,
- this one will get replaced. If not, we'll insert this
- item into the main tree at the end. */
- info->entry = new_item;
- } else {
- BM_FreeEntry(context, new_item);
- }
- new_item = bm_NewAlias(info->entry);
- if (!new_item) return NULL;
- }
- }
- }
- }
-
- /* replace the quotes */
- if (end) *end = '"';
- return new_item;
- }
-
- static void
- bm_check_nickname(MWContext* context, BM_Entry* entry, char* str)
- {
- char* ptr = strcasestr(str, "NICKNAME=\"");
- char* end;
- if (ptr) {
- ptr += 10;
- end = XP_STRCHR(ptr, '"');
- if (end) {
- *end = '\0';
- BM_SetNickName(context, entry, ptr);
- *end = '"';
- }
- }
- }
-
- /*
- // Replace all occurances of escaped quotes (%22) with explicit quotes (").
- // Do not replace beyond the end of the " delimited string.
- //
- // Return a ptr to the position after the last occurance of an escaped quote.
- */
- static char *bm_explicit_quotes( char *pszSource )
- {
- char *pszCsr = NULL;
- char *pszLast = NULL;
-
- if( !pszSource )
- {
- return pszSource;
- }
-
-
- pszLast = XP_STRCHR( pszSource, '"' );
-
- while( (pszCsr = strstr( pszSource, "%22" )) && (pszCsr < pszLast) )
- {
- *pszCsr = '"';
- pszSource = pszCsr + 1;
- XP_MEMMOVE( pszSource, pszSource+2, XP_STRLEN(pszSource+2)+1 );
- }
-
- return pszSource;
- }
-
-
- static BM_Entry*
- bm_read_url(MWContext* context, XP_File fp, char* buffer, char* ptr,
- const char* relative_url)
- {
- char* endQuote;
- char* gtr_than;
- char* parseString;
- char* end;
- char* url;
- char *pszAfterLastEscapedQuote;
- BM_Entry* new_item = NULL;
-
- /* find next quote */
- parseString = ptr + 6;
-
- /* Replace escaped quotes with explicit ones */
- pszAfterLastEscapedQuote = bm_explicit_quotes( parseString );
-
- endQuote = XP_STRCHR(pszAfterLastEscapedQuote, '"');
-
- if (endQuote) {
-
- /* temporarily terminate */
- *endQuote = '\0';
-
- url = NET_MakeAbsoluteURL((char*)relative_url, parseString);
- if (url) {
- new_item = BM_NewUrl(NULL, url, NULL, 0);
- XP_FREE(url);
- }
- if (!new_item) return NULL;
-
- /* find '>' and the name will be right after it */
- gtr_than = XP_STRCHR(endQuote + 1, '>');
- if (gtr_than) {
- /* find the end of the name */
- end = strcasestr(gtr_than, "</A>");
- if (end) {
- *end = '\0';
- StrAllocCopy(new_item->name, XP_StripLine(gtr_than + 1));
- /* terminate at beginning of name since there
- is nothing interesting after that */
- *gtr_than = '\0';
- } else {
- StrAllocCopy(new_item->name,
- XP_StripLine(gtr_than + 1));
-
- /* what happens if this breaks?? this is bogus stuff I don't
- know what to do with */
- XP_FileReadLine(buffer, READ_BUFFER_SIZE, fp);
- end = strcasestr(buffer, "</A>");
-
- if (end) *end = '\0';
-
- StrAllocCat(new_item->name, XP_StripLine(buffer));
- }
- }
-
- parseString = endQuote + 1;
-
- new_item->d.url.target = bm_target(parseString, FALSE);
-
- new_item->addition_date = bm_addition_date(parseString);
-
- new_item->d.url.last_visit = bm_last_date(parseString, FALSE);
- new_item->d.url.last_modified = bm_last_date(parseString, TRUE);
- if (new_item->d.url.last_modified == 0) {
- new_item->d.url.last_modified = new_item->d.url.last_visit;
- }
-
- new_item = bm_check_read_alias(context, new_item, parseString);
-
- /* replace the quotes */
- *endQuote = '"';
- }
-
- return new_item;
- }
-
-
- static BM_Entry*
- bm_read_address(MWContext* context, XP_File fp, char* buffer, char* ptr)
- {
- char* endQuote;
- char* gtr_than;
- char* parseString;
- char* end;
- char* url;
- BM_Entry* new_item = NULL;
-
- XP_ASSERT(context->type == MWContextAddressBook);
-
- /* find next quote */
- parseString = ptr + 6;
-
- endQuote = XP_STRCHR(parseString, '"');
- if (endQuote) {
- *endQuote = '\0';
-
- url = parseString;
-
- if (strncasecomp(url, "mailto:", 7) == 0) {
- url += 7;
- }
-
- new_item = bm_NewAddress(NULL, url);
- if (!new_item) return NULL;
-
- /* find '>' and the name will be right after it */
- gtr_than = XP_STRCHR(endQuote + 1, '>');
- if (gtr_than) {
- *gtr_than++ = '\0';
- /* find the end of the name */
- end = strcasestr(gtr_than, "</A>");
- if (end) {
- *end = '\0';
- StrAllocCopy(new_item->name, XP_StripLine(gtr_than));
- }
- }
-
- parseString = endQuote + 1;
-
- new_item = bm_check_read_alias(context, new_item, parseString);
-
- if (!BM_ISALIAS(new_item)) {
- bm_check_nickname(context, new_item, parseString);
- }
- }
-
- return new_item;
- }
-
-
- /* ptr should point to the chars "<Hx" */
- static BM_Entry*
- bm_read_header(MWContext* context, char* buffer, char* ptr)
- {
- BM_Frame* f = GETFRAME(context);
- char* gtr_than;
- char* end;
- BM_Entry* new_item = NULL;
-
-
- /* find the beginning of the name */
- gtr_than = XP_STRCHR(ptr + 3, '>');
-
- /* find the end of the name */
- if (gtr_than) {
- end = strcasestr(gtr_than, "</H");
- }
-
- if (gtr_than && end) {
- /* temporarily NULL the name string */
- *end = '\0';
-
- new_item = BM_NewHeader(gtr_than + 1);
-
- if (!new_item)
- return NULL;
-
- *gtr_than = '\0';
-
- new_item->d.header.target = bm_target(buffer, FALSE);
-
- new_item->addition_date = bm_addition_date(buffer);
-
- if (bm_is_folded(buffer))
- BM_SETFLAG(new_item, BM_ATTR_FOLDED);
- else
- BM_CLEARFLAG(new_item, BM_ATTR_FOLDED);
-
- new_item = bm_check_read_alias(context, new_item, buffer);
-
- if (!BM_ISALIAS(new_item)) {
- if (context->type == MWContextAddressBook) {
- bm_check_nickname(context, new_item, buffer);
- } else {
- if (strcasestr(buffer, "MENUHEADER")) f->menuheader = new_item;
- if (strcasestr(buffer, "NEWITEMHEADER")) f->addheader = new_item;
- }
- }
-
- }
-
- return new_item;
- }
-
-
-
- static void
- bm_read_description(BM_Entry* new_item, char* buffer )
- {
- char* ptr;
- char* end;
- int length;
-
- /* assume the rest is descriptions; ignore if item is not a reasonable
- type */
-
- if (!new_item || !buffer) return;
-
- switch (new_item->type) {
- case BM_TYPE_HEADER:
- case BM_TYPE_URL:
- case BM_TYPE_ADDRESS:
-
- length = XP_STRLEN(buffer);
-
- /* skip <DL> if present */
- if (*buffer == '<') {
- buffer += 4;
- length -= 4;
- }
-
- if (length <= 0) return;
-
- end = buffer + length - 1;
-
- /* check for <BR> on the end and remove it also add a return */
- if (*end == '>') {
- end -= 3;
- XP_STRCPY(end, LINEBREAK);
- end += LINEBREAK_LEN;
- *end = '\0';
- } else {
- end++;
- XP_STRCPY(end, LINEBREAK);
- end += LINEBREAK_LEN;
- *end = '\0';
- }
-
- /* go through and turn < into '<' */
- for (ptr = buffer, end = buffer; *end != '\0'; end++) {
- if (!strncasecomp(end, "<", 4)) {
- end += 3;
- *ptr++ = '<';
- } else {
- *ptr++ = *end;
- }
- }
- *ptr = '\0'; /* terminate */
- StrAllocCat(new_item->description, buffer);
- }
- }
-
-
-
-
- /* Find the next entry after this one, where "next" means "the one that would
- show up on the next line if we didn't fold any headers". Also, this will
- wrap around from the end back to the beginning. In other words, it will
- never return NULL. */
- static BM_Entry*
- bm_GetNextSpanningWrapping(MWContext* context, BM_Entry* at)
- {
- if (BM_ISHEADER(at) && at->d.header.children) return at->d.header.children;
- if (at->next) return at->next;
- do {
- at = at->parent;
- if (at && at->next) {
- return at->next;
- }
- } while (at);
- return BM_GetRoot(context);
- }
-
-
-
- static XP_Bool
- bm_StringMatches(MWContext* context, BM_FindInfo* findInfo, const char* str) {
- char* ptr;
- INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
- if (!str) return FALSE;
- if (findInfo->matchCase) {
- ptr = INTL_Strstr(INTL_GetCSIWinCSID(c), str, findInfo->textToFind);
- } else {
- ptr = INTL_Strcasestr(INTL_GetCSIWinCSID(c), str, findInfo->textToFind);
- }
- if (!ptr) return FALSE;
- if (findInfo->matchWholeWord) {
- XP_ASSERT(ptr >= str);
- XP_ASSERT(ptr + XP_STRLEN(findInfo->textToFind) <= str + XP_STRLEN(str));
- if (ptr != str && !isspace(ptr[-1]) && !ispunct(ptr[-1])) return FALSE;
- ptr += XP_STRLEN(findInfo->textToFind);
- if (*ptr != '\0' && !isspace(*ptr) && !ispunct(*ptr)) return FALSE;
- }
- return TRUE;
- }
-
-
- static XP_Bool
- bm_IsMatch(MWContext* context, BM_Entry* entry, BM_FindInfo* findInfo)
- {
-
- if(!context)
- return FALSE;
-
- if (BM_ISALIAS(entry)) entry = entry->d.alias.original;
- if (findInfo->checkNickname) {
- if (bm_StringMatches(context, findInfo, entry->nickname)) return TRUE;
- }
- if (findInfo->checkName) {
- if (bm_StringMatches(context, findInfo, BM_GetName(entry))) return TRUE;
- }
- if (findInfo->checkLocation && BM_ISURL(entry)) {
- if (bm_StringMatches(context, findInfo, entry->d.url.address)) return TRUE;
- }
- if (findInfo->checkDescription) {
- if (bm_StringMatches(context, findInfo, entry->description)) return TRUE;
- }
- return FALSE;
- }
-
- static BM_Entry*
- bm_DoFindBookmark_1(MWContext* context, BM_Entry* at, BM_FindInfo* findInfo) {
- BM_Entry* start = at;
- if (!at) return NULL;
- do {
- if (bm_IsMatch(context, at, findInfo)) return at;
- at = bm_GetNextSpanningWrapping(context, at);
- } while (at != start);
- return NULL;
- }
-
- /* reads an item from fp using the specified buffer and relative_url */
- static void
- bm_ReadFromHTML(MWContext* context,
- XP_File fp,
- BM_Entry* item,
- char* buffer,
- const char* relative_url)
- {
- BM_Frame* f = GETFRAME(context);
- BM_Entry* new_item = NULL;
- char* buffer_ptr;
- char* ptr;
- uint16 type;
-
- /* read loop */
- while (XP_FileReadLine(buffer, READ_BUFFER_SIZE, fp)) {
- buffer_ptr = XP_StripLine(buffer);
-
- type = bm_tokenize_line(context, buffer_ptr, &ptr);
-
- switch (type) {
- case BM_TYPE_URL:
- new_item = bm_read_url(context, fp, buffer_ptr, ptr, relative_url);
- break;
-
- case BM_TYPE_ADDRESS:
- new_item = bm_read_address(context, fp, buffer_ptr, ptr);
- break;
-
- case BM_TYPE_HEADER:
- new_item = bm_read_header(context, buffer_ptr, ptr);
- break;
-
- case BM_TYPE_SEPARATOR:
- if (context->type == MWContextBookmarks) {
- new_item = bm_NewSeparator();
- }
- break;
-
- case BM_HEADER_END:
- if (item != f->gBookmarks) return;
- break;
-
- case BM_UNKNOWN:
- if (new_item)
- bm_read_description(new_item, buffer_ptr);
- else if (item)
- bm_read_description(item, buffer_ptr);
- break;
- }
-
- /* test for insertable item -- nb you'll need
- to update this if you add new types/items */
- if (new_item && (type == BM_TYPE_URL ||
- type == BM_TYPE_HEADER ||
- type == BM_TYPE_SEPARATOR ||
- type == BM_TYPE_ADDRESS)) {
- if (!item) {
- if (!f->gBookmarks) {
- if (new_item->type == BM_TYPE_HEADER) {
- f->gBookmarks = new_item;
- if (context->type == MWContextBookmarks) {
- f->menuheader = f->addheader = new_item;
- }
- goto SKIP;
- } else {
- (void) BM_GetRoot(context); /* Has side effect of creating
- root header. */
- if (!f->gBookmarks) return;
- }
- }
- item = f->gBookmarks;
- }
-
- if (context->type == MWContextBookmarks) {
- bm_AppendChildToHeader(context, item, new_item);
- } else {
- bm_AddChildToHeaderSorted(context, item, new_item);
- }
-
- SKIP:
- /* if it's a header, recurse */
- if (new_item->type == BM_TYPE_HEADER) {
- bm_ReadFromHTML(context, fp, new_item, buffer, relative_url);
- }
- }
- }
- }
-
- static int
- bm_WriteAsHTML(MWContext* context, XP_File fp, BM_Entry* item, int32 level,
- XP_Bool isalias);
-
-
- static int
- bm_write_ok(const char* str, int length, XP_File fp)
- {
- if (length < 0) length = XP_STRLEN(str);
- if ((int) XP_FileWrite(str, length, fp) < length) return -1;
- return 0;
- }
-
-
- #define WRITE(str, length, fp) \
- if (bm_write_ok((str), (length), (fp)) < 0) return -1
-
- static int
- bm_write_alias_info(MWContext* context, XP_File fp, BM_Entry* entry,
- XP_Bool isalias)
- {
- bm_alias_info* info;
- XP_ASSERT(!isalias || (entry->flags & BM_ATTR_HASALIASES));
- if (entry->flags & BM_ATTR_HASALIASES) {
- if (!isalias) {
- /* Well, we think we have some aliases, but we can't be sure. Let's
- make sure. */
- if (BM_CountAliases(context, entry) == 0) return 0;
- }
- info = bm_find_writealias_info(context, entry);
- WRITE(isalias ? " ALIASOF=\"" : " ALIASID=\"", -1, fp);
- WRITE(info->id, -1, fp);
- WRITE("\"", -1, fp);
- }
- return 0;
- }
-
-
- static int
- bm_write_nickname(MWContext* context, XP_File fp, BM_Entry* entry,
- XP_Bool isalias)
- {
- if (context->type == MWContextAddressBook && !isalias &&
- entry->nickname && *entry->nickname) {
- WRITE(" NICKNAME=\"", -1, fp);
- WRITE(entry->nickname, -1, fp);
- WRITE("\"", -1, fp);
- }
- return 0; /* XXX This was left out. Is is 0 right? */
- }
-
-
-
- static int
- bm_write_html_header(MWContext* context, XP_File fp, BM_Entry* item,
- int32 level, XP_Bool isalias)
- {
- BM_Frame* f = GETFRAME(context);
- char buffer[16];
- int32 i;
- BM_Entry* child;
- char* target;
- int status;
-
- XP_ASSERT(BM_ISHEADER(item));
-
- target = BM_GetTarget(item, FALSE);
-
- if (level != 0) {
- if (item->name) {
- WRITE("<DT><H3", -1, fp);
- /* write folded state */
- if (item->flags & BM_ATTR_FOLDED) {
- WRITE(" FOLDED", -1, fp);
- }
-
- if (item == f->menuheader) {
- WRITE(" MENUHEADER", -1, fp);
- }
- if (item == f->addheader) {
- WRITE(" NEWITEMHEADER", -1, fp);
- }
-
- status = bm_write_alias_info(context, fp, item, isalias);
- if (status < 0) return status;
-
- status = bm_write_nickname(context, fp, item, isalias);
- if (status < 0) return status;
-
- /* write target */
- if ((target)&&(target[0] != '\0'))
- {
- WRITE(" TARGET=\"", -1, fp);
- WRITE(target, -1, fp);
- WRITE("\"", -1, fp);
- }
-
- if (context->type == MWContextBookmarks) {
- /* write addition date */
- WRITE(" ADD_DATE=\"", -1, fp);
- XP_SPRINTF(buffer, "%ld\"", item->addition_date);
- WRITE(buffer, XP_STRLEN(buffer), fp);
- }
- WRITE(">", -1, fp);
-
- /* write name */
- WRITE(item->name, XP_STRLEN(item->name), fp);
- WRITE("</H3>", -1, fp);
- WRITE(LINEBREAK, LINEBREAK_LEN, fp);
- }
- }
-
- /* write description if there is one */
- if (item->description) {
- char *ptr = XP_StripLine(item->description);
-
- WRITE("<DD>", -1, fp);
-
- for (; *ptr != '\0'; ptr++) {
- if (*ptr == '<') {
- WRITE("<", -1, fp);
- } else if (*ptr == '\n') {
- WRITE("<BR>", -1, fp);
- WRITE(LINEBREAK, LINEBREAK_LEN, fp);
- } else {
- WRITE(ptr, 1, fp);
- }
- }
- WRITE(LINEBREAK, LINEBREAK_LEN, fp);
- }
-
- if (!isalias) {
- /* write children out */
- for (i = 0; i < level; i++) {
- WRITE(" ", -1, fp); /* indent */
- }
- WRITE("<DL><p>" LINEBREAK, -1, fp);
-
- for (child = item->d.header.children; child ; child = child->next) {
- bm_WriteAsHTML(context, fp, child, level + 1, FALSE);
- }
-
- for (i = 0; i < level; i++) {
- WRITE(" ", -1, fp);
- }
-
- WRITE("</DL><p>" LINEBREAK, -1, fp);
- }
- return 0;
- }
-
- static int
- bm_write_separator(XP_File fp)
- {
- WRITE("<HR>", -1, fp);
- WRITE(LINEBREAK, LINEBREAK_LEN, fp);
- return 0;
- }
-
- static int
- bm_write_address( char *pszAddress, XP_File fp )
- {
- /*
- // Replace explicit quotes with escaped quotes before writing the address.
- // For example:
- // javascript:netscape.plugin.composer.Document.editDocument("http://myserver.com/docs/schedule.html")
- // is converted to:
- // javascript:netscape.plugin.composer.Document.editDocument(%20http://myserver.com/docs/schedule.html%20)
- */
-
- int iBufPos, iLen = 0;
- char * pszCsr = pszAddress;
- char * pszBuf = NULL;
-
- if( !pszAddress || !fp )
- {
- return 0;
- }
-
- if( !XP_STRCHR( pszAddress, '"' ) )
- {
- /* No quotes to convert, so just write it and return. */
-
- WRITE( pszAddress, -1, fp );
- return 0;
- }
-
- /*
- // Calculate the size of the new string.
- */
- iLen = XP_STRLEN( pszAddress );
- while( *pszCsr )
- {
- if( *pszCsr == '"' )
- {
- iLen += 2;
- }
- pszCsr++;
- }
-
- pszBuf = (char *)XP_ALLOC( iLen+1 );
- if( !pszBuf )
- {
- return 0;
- }
-
- /*
- // Copy the url while converting explicit quotes to escaped quotes.
- */
- iBufPos = 0;
- pszCsr = pszAddress;
- while( *pszCsr )
- {
- if( *pszCsr == '"' )
- {
- pszBuf[iBufPos] = '%';
- pszBuf[++iBufPos] = '2';
- pszBuf[++iBufPos] = '2';
- }
- else
- {
- pszBuf[iBufPos] = *pszCsr;
- }
-
- iBufPos++;
- pszCsr++;
- }
- pszBuf[iBufPos] = 0;
-
- /* Finally write out the converted address */
-
- WRITE( pszBuf, -1, fp );
-
- XP_FREE( pszBuf );
- }
-
- /* writes out a URL entry to look like:
- *
- * <DT><A HREF="http://www.ncsa.uiuc.edu/radio/radio.html" \
- * ADD_DATE="777240414" LAST_VISIT="802992591">Internet Talk Radio</A>
- *
- */
- static int
- bm_write_url_or_address(MWContext* context, XP_File fp, BM_Entry* item,
- XP_Bool isalias)
- {
- char buffer[16];
- char* address;
- char* target;
- int status;
-
- address = BM_GetAddress(item);
- target = BM_GetTarget(item, FALSE);
-
- if (address) {
- WRITE("<DT>", -1, fp);
-
- /* write address */
- WRITE("<A HREF=\"", -1, fp);
- if (context->type == MWContextAddressBook) {
- WRITE("mailto:", -1, fp);
- }
- bm_write_address(address, fp);
- WRITE("\"", -1, fp);
-
- /* write target */
- if ((target)&&(target[0] != '\0'))
- {
- WRITE(" TARGET=\"", -1, fp);
- WRITE(target, -1, fp);
- WRITE("\"", -1, fp);
- }
-
- status = bm_write_alias_info(context, fp, item, isalias);
- if (status < 0) return status;
-
- status = bm_write_nickname(context, fp, item, isalias);
- if (status < 0) return status;
-
- if (BM_ISURL(item)) {
- /* write the addition date */
- WRITE(" ADD_DATE=\"", -1, fp);
- XP_SPRINTF(buffer, "%ld", item->addition_date);
- WRITE(buffer, -1, fp);
- WRITE("\"", -1, fp);
-
- /* write the last visited date */
- WRITE(" LAST_VISIT=\"", -1, fp);
- XP_SPRINTF(buffer, "%ld\"", item->d.url.last_visit);
- WRITE(buffer, -1, fp);
-
- /* write the last modified date */
- WRITE(" LAST_MODIFIED=\"", -1, fp);
- XP_SPRINTF(buffer, "%ld\"", item->d.url.last_modified);
- WRITE(buffer, -1, fp);
- }
- WRITE(">", -1, fp);
-
- /* write the name */
-
- if (item->name) {
- WRITE(item->name, -1, fp);
- } else {
- if (BM_ISURL(item)) {
- WRITE(item->d.url.address, -1, fp);
- } else {
- XP_ASSERT(BM_ISADDRESS(item));
- WRITE(item->d.address.address, -1, fp);
- }
- }
-
- WRITE("</A>", -1, fp);
- WRITE(LINEBREAK, LINEBREAK_LEN, fp);
-
- /* write description if there is one */
- if (item->description) {
- char *ptr = XP_StripLine(item->description);
-
- WRITE("<DD>", -1, fp);
-
- for (; *ptr != '\0'; ptr++) {
- if (*ptr == '<') {
- WRITE("<", -1, fp);
- } else if (*ptr == '\n') {
- WRITE("<BR>", -1, fp);
- WRITE(LINEBREAK, LINEBREAK_LEN, fp);
- } else {
- WRITE(ptr, 1, fp);
- }
- }
- WRITE(LINEBREAK, LINEBREAK_LEN, fp);
- }
- }
- return 0;
- }
-
-
- /* writes an item into fp at the specified indentation level */
- static int
- bm_WriteAsHTML(MWContext* context, XP_File fp, BM_Entry* item, int32 level,
- XP_Bool isalias)
- {
- int32 i;
- int status = 0;
-
- /* indent */
- if (!isalias) {
- for (i = 0; i < level; i++) {
- WRITE(" ", -1, fp);
- }
- }
-
- switch (item->type) {
- case BM_TYPE_HEADER:
- status = bm_write_html_header(context, fp, item, level, isalias);
- break;
-
- case BM_TYPE_SEPARATOR:
- status = bm_write_separator(fp);
- break;
-
- case BM_TYPE_URL:
- case BM_TYPE_ADDRESS:
- status = bm_write_url_or_address(context, fp, item, isalias);
- break;
-
- case BM_TYPE_ALIAS:
- XP_ASSERT(!isalias);
- status = bm_WriteAsHTML(context, fp, item->d.alias.original, level, TRUE);
- break;
- }
- return status;
- }
-
- /* clears the selected state of parent and all of it's children
- if refresh is TRUE, the FE is called to redraw necessary items
- count should match the index of parent in the visible tree. count will
- be NULL if a parent is folded. */
- PRIVATE void
- bm_ClearSelection(MWContext* context, BM_Entry* parent, XP_Bool refresh, int32* count)
- {
- BM_Frame* f = GETFRAME(context);
- BM_Entry* child;
- XP_ASSERT(parent);
- XP_ASSERT(BM_ISHEADER(parent));
-
- if (parent->flags & BM_ATTR_SELECTED) {
- BM_CLEARFLAG(parent, BM_ATTR_SELECTED);
- if (refresh && count) bm_refresh(context, *count, *count);
- f->gSelectionCount = -9999;
- }
-
- if (count) (*count)++;
-
- if (BM_ISFOLDED(parent)) count = NULL;
-
- for (child = parent->d.header.children ; child ; child = child->next) {
- if (child->type != BM_TYPE_HEADER) {
- if (child->flags & BM_ATTR_SELECTED) {
- BM_CLEARFLAG(child, BM_ATTR_SELECTED);
- if (refresh && count) bm_refresh(context, *count, *count);
- f->gSelectionCount = -9999;
- }
- if (count) (*count)++;
- } else {
- bm_ClearSelection(context, child, refresh, count);
- }
- }
- }
-
- PRIVATE void
- bm_SelectAll(MWContext* context, BM_Entry* parent)
- {
- BM_Frame* f = GETFRAME(context);
- BM_Entry* child;
-
- XP_ASSERT(parent);
- XP_ASSERT(parent->type == BM_TYPE_HEADER);
-
- child = parent->d.header.children;
- if (!BM_ISSELECTED(parent))
- {
- BM_SETFLAG(parent, BM_ATTR_SELECTED);
- f->gSelectionCount++;
- f->gSelectionMask |= BM_TYPE_HEADER;
- }
-
- while (child)
- {
- if (BM_ISHEADER(child))
- bm_SelectAll(context, child);
- else
- {
- if (!(child->flags & BM_ATTR_SELECTED))
- {
- BM_SETFLAG(child, BM_ATTR_SELECTED);
- f->gSelectionCount++;
- f->gSelectionMask |= child->type;
- }
- }
- child = child->next;
- }
- }
-
- PUBLIC void
- BM_SelectAll(MWContext* context, XP_Bool refresh)
- {
- BM_Entry* root;
- CHKCONTEXTVOID(context);
-
- root = BM_GetRoot(context);
-
- if (root)
- {
- bm_SelectAll(context, root);
- if (refresh)
- bm_refresh(context, 1, BM_LAST_CELL);
- }
- }
-
- static void
- bm_TellGoingAway(MWContext* context, BM_Entry* entry, void* closure)
- {
- BM_Frame* f = GETFRAME(context);
- if (entry == f->menuheader) {
- BM_SetMenuHeader(context, BM_GetRoot(context));
- }
- if (entry == f->addheader) {
- BM_SetAddHeader(context, BM_GetRoot(context));
- }
- BMFE_EntryGoingAway(context, entry);
- if (entry->nickname) {
- BM_SetNickName(context, entry, NULL); /* Causes the nickname hash to be
- cleared, adding undo stuff to
- bring it back if this entry
- somehow gets brought back. */
- XP_ASSERT(entry->nickname == NULL);
- }
- #ifdef DEBUG
- /* Confirm that we are not deleting any dangling aliases. */
- if (entry->flags & BM_ATTR_HASALIASES) {
- int32 count = BM_CountAliases(context, entry);
- if (count) {
- BM_Entry* deleteroot = (BM_Entry*) closure;
- if (BM_ISHEADER(deleteroot)) {
- /* Reduce the count by the number of aliases that we're going to
- delete. */
- count -= bm_CountAliases_1(deleteroot, entry);
- }
- XP_ASSERT(count == 0);
- }
- }
- #endif /* DEBUG */
- }
-
- /* free's a bmlist entry */
- PRIVATE void
- bm_ShallowFreeEntry(BM_Entry* entry)
- {
- if (entry) {
- XP_ASSERT(entry->next == NULL);
- XP_ASSERT(entry->nickname == NULL);
-
- FREEIF(entry->name);
- FREEIF(entry->description);
- switch (entry->type) {
- case BM_TYPE_HEADER:
- XP_ASSERT(entry->d.header.children == NULL);
- break;
-
- case BM_TYPE_URL:
- FREEIF(entry->d.url.address);
- FREEIF(entry->d.url.content_type);
- break;
-
- case BM_TYPE_ADDRESS:
- FREEIF(entry->d.address.address);
- break;
- }
- XP_FREE(entry);
- }
- }
-
- PRIVATE void
- bm_ReallyFreeEntry(void* data)
- {
- BM_Entry* entry = (BM_Entry*) data;
- while (entry) {
- BM_Entry* next = entry->next;
- entry->next = NULL;
- if (BM_ISHEADER(entry)) {
- /* free all the children */
- bm_ReallyFreeEntry(entry->d.header.children);
- entry->d.header.children = NULL;
- }
- bm_ShallowFreeEntry(entry);
- entry = next;
- }
- }
-
-
- typedef struct bm_free_info {
- BM_Entry* entry;
- XP_Bool usedFromUndo;
- } bm_free_info;
-
- static int
- bm_cancel_free(void* closure)
- {
- bm_free_info* info = (bm_free_info*) closure;
- info->usedFromUndo = TRUE;
- return 0;
- }
-
-
- static void
- bm_free_freeit(void* closure)
- {
- bm_free_info* info = (bm_free_info*) closure;
- if (!info->usedFromUndo) bm_ReallyFreeEntry(info->entry);
- XP_FREE(info);
- }
-
-
- /* free's a BM_Entry and all of its succeeding siblings... if it's a
- header, it frees all of its children. However, actually this
- does nothing, but logs an event in the undo queue. When the event gets
- freed, then we know that nothing in the undo chain needs this thing,
- so *then* we can free it.*/
- void
- BM_FreeEntry(MWContext* context, BM_Entry* entry)
- {
- BM_Frame* f = GETFRAME(context);
- if (!entry) return;
-
- bm_start_batch(context);
- bm_EachEntryDo_1(context, entry, bm_TellGoingAway, entry);
-
- if (f->undo) {
- bm_free_info* info = XP_NEW_ZAP(bm_free_info);
- if (!info) {
- UNDO_DiscardAll(f->undo);
- bm_ReallyFreeEntry(entry);
- } else {
- info->entry = entry;
- UNDO_LogEvent(f->undo, bm_cancel_free, bm_free_freeit, info, NULL, NULL);
- }
- } else {
- bm_ReallyFreeEntry(entry);
- }
- bm_end_batch(context);
- }
-
-
-
- int
- BM_InitializeBookmarksContext(MWContext* context)
- {
- BM_Frame* f;
- XP_ASSERT(context);
- if (!context) return -1; /* ### Need better error code? */
- f = XP_NEW_ZAP(BM_Frame);
- if (!f) return MK_OUT_OF_MEMORY;
- XP_ASSERT(context->bmframe == NULL);
- f->undo = UNDO_Create(10);
- if (!f->undo) goto FAIL;
- f->nicknameTable = XP_HashTableNew(100, XP_StringHash, bm_string_cmp);
- if (!f->nicknameTable) goto FAIL;
- f->errorSavingBookmarks = FALSE;
- f->enSortType = BM_Sort_Natural;
- f->bSorting = FALSE;
- context->bmframe = f;
- f->next = ContextList;
- ContextList = context;
- (void) BM_GetRoot(context); /* Has side effect of creating root header. */
- bm_refresh(context, 1, BM_LAST_CELL);
- return 0;
- FAIL:
- if (f->undo) UNDO_Destroy(f->undo);
- if (f->nicknameTable) XP_HashTableDestroy(f->nicknameTable);
- XP_FREE(f);
- return MK_OUT_OF_MEMORY;
- }
-
- void
- BM_CleanupBookmarksContext(MWContext* context)
- {
- BM_Frame* f;
- MWContext** tmp;
- CHKCONTEXTVOID(context);
- BM_SaveBookmarks(context, NULL);
-
- /* This cleanup code can be slow and
- inefficient. Since we're gonna exit soon
- anyway, let's not bother doing this stuff.
- ### - DMB - Let's, at least for debug
- detection of meory leaks. How slow could it
- be? */
- f = GETFRAME(context);
- UNDO_Destroy(f->undo);
- f->undo = NULL;
- BM_FreeEntry(context, f->gBookmarks);
- if (f->savetimer) {
- FE_ClearTimeout(f->savetimer);
- f->savetimer = NULL;
- }
-
- f->gBookmarks = NULL;
- if (f->aliasTable) {
- bm_clear_alias_info(context);
- XP_HashTableDestroy(f->aliasTable);
- }
- if (f->nicknameTable) {
- XP_HashTableDestroy(f->nicknameTable);
- }
-
- for (tmp = &ContextList ; *tmp ; tmp = &(f->next)) {
- f = GETFRAME(*tmp);
- if (*tmp == context) {
- (*tmp)->bmframe = NULL;
- *tmp = f->next;
- XP_FREE(f);
- return;
- }
- }
- XP_ASSERT(0);
- }
-
-
- /* returns TRUE if the bookmarks have been modified since
- the file was read, FALSE otherwise */
- PUBLIC XP_Bool
- BM_Modified(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- CHKCONTEXT(context);
- return f ? f->gBookmarksModified : FALSE;
- }
-
- static void
- bm_UpdateTimeStamp(MWContext* context, BM_Entry* entry, void* closure)
- {
- BM_Date cur_time = *(BM_Date *)closure;
- BM_Frame* f = GETFRAME(context);
- int32 oldstate;
-
- if (!entry) return;
-
- oldstate = BM_GetChangedState(entry);
- entry->d.url.last_visit = cur_time;
- if (entry->d.url.last_modified == 0) {
- /* Well, this current visitation is a good enough estimate for the modification time. */
- entry->d.url.last_modified = cur_time;
- }
-
- /* Deliberately *don't* call bm_SetModified here; we don't want to cause
- the file to be saved soon for this trivial change. Just turn on the
- modified bit so that we know things will be saved eventually. */
- f->gBookmarksModified = TRUE;
-
- if (BM_GetChangedState(entry) != oldstate) {
- bm_entry_changed(context, entry);
- }
- }
-
- /* checks the bmlist for a url and updates the last accessed time */
- PUBLIC void
- BM_UpdateBookmarksTime(URL_Struct* URL_s, BM_Date cur_time)
- {
- MWContext* context;
- BM_Frame* f;
-
- if (!URL_s) return;
-
- for (context = ContextList ; context ; context = f->next) {
- f = GETFRAME(context);
- if (context->type != MWContextBookmarks) continue;
- bm_FindItemStub(context, BM_GetRoot(context), URL_s->address, bm_UpdateTimeStamp, (void *)&cur_time);
- }
- }
-
-
- /* returns the total number of items in the tree */
- PUBLIC int32
- BM_GetCount(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- CHKCONTEXT(context);
- if (!f) return 0;
- if (f->gCount <= 0) {
- f->gCount = bm_CountChildren(BM_GetRoot(context), FALSE);
- }
- return f->gCount;
- }
-
- /* returns the number of items in the tree that are presently
- visible */
- PUBLIC int32
- BM_GetVisibleCount(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- CHKCONTEXT(context);
- if (!f) return 0;
- if (f->gVisCount <= 0) {
- f->gVisCount = bm_CountChildren(BM_GetRoot(context), TRUE);
- }
- return f->gVisCount;
- }
-
-
-
-
-
- static void
- bm_InsertItemAfter(MWContext* context, BM_Entry* insert_after,
- BM_Entry* insertee, XP_Bool sync)
- {
- BM_Frame* f = GETFRAME(context);
- CHKCONTEXTVOID(context);
-
- XP_ASSERT(insertee);
- if (!insertee) return;
-
- /* insert after the item if specified */
- if (insert_after)
- {
- BM_Entry* tmp;
- BM_Entry* parent;
-
- if (insert_after->parent == NULL)
- {
- /* insert as first child, displayed below header */
- tmp = insert_after->d.header.children;
- parent = insert_after;
- parent->d.header.childCount++;
- parent->d.header.children = insertee;
- }
- else
- {
- tmp = insert_after->next;
- parent = insert_after->parent;
-
- if (parent)
- {
- parent->d.header.childCount++;
- if (!tmp)
- parent->d.header.lastChild = insertee;
- }
- insert_after->next = insertee;
- }
- insertee->next = tmp;
- insertee->parent = parent;
-
- if( !f->bSorting )
- insertee->iNaturalIndex = g_iNaturalIndexPool++;
-
- BMFE_BookmarkMenuInvalid(context);
- bm_LogDeleteChild(context, parent, insertee);
- }
- else
- bm_AppendChildToHeader(context, BM_GetRoot(context), insertee);
-
- bm_SetModified(context, TRUE);
- if (sync)
- bm_SyncCount(context);
- }
-
- /* insert an item after another item in the bmlist
- if the insert_after item is NULL the item
- will be inserted at the end of the bookmarks */
- PUBLIC void
- BM_InsertItemAfter(MWContext* context, BM_Entry* insert_after, BM_Entry* insertee)
- {
- CHKCONTEXTVOID(context);
- bm_start_batch(context);
- bm_InsertItemAfter(context, insert_after, insertee, TRUE);
- bm_end_batch(context);
- }
-
- /* insert an item in a header if "insert_after" is a
- Header type, or after the item if "insert after" is
- not a header type.
- if the insert_after item is NULL or not found the item
- will be inserted at the end of the bookmarks */
- PUBLIC void
- BM_InsertItemInHeaderOrAfterItem( MWContext* context,
- BM_Entry* insert_after,
- BM_Entry* insertee)
- {
- CHKCONTEXTVOID(context);
- XP_ASSERT(insertee);
-
- bm_start_batch(context);
- if (insert_after && insert_after->type == BM_TYPE_HEADER)
- bm_AppendChildToHeader(context, insert_after, insertee);
- else
- BM_InsertItemAfter(context, insert_after, insertee);
- bm_SyncCount(context);
- bm_end_batch(context);
- }
-
- void remove_to(MWContext* context, BM_Entry* entry, void* to)
- {
- BM_Entry* moveTo = (BM_Entry*)to;
- BM_Entry* parent;
-
- XP_ASSERT(entry);
-
- parent = entry->parent;
- if (parent)
- BM_RemoveChildFromHeader(context, parent, entry);
-
- bm_AppendChildToHeader(context, moveTo, entry);
- }
-
-
-
- static int
- bm_get_max_depth_1(BM_Entry* entry)
- {
- int result = 0;
- for (; entry ; entry = entry->next) {
- if (BM_ISHEADER(entry) && !BM_ISFOLDED(entry)) {
- int value = bm_get_max_depth_1(entry->d.header.children);
- if (result < value) result = value;
- }
- }
- return result + 1;
- }
-
- int
- BM_GetMaxDepth(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- CHKCONTEXT(context);
- if (!f) return 0;
- if (f->max_depth == 0) {
- f->max_depth = bm_get_max_depth_1(f->gBookmarks);
- }
- return f->max_depth;
- }
-
-
- PUBLIC XP_Bool
- BM_IsDragEffectBox(MWContext* context, int line, XP_Bool under)
- {
- BM_Entry* entry;
- CHKCONTEXT(context);
- if (line <= 0) return FALSE;
- entry = BM_AtIndex(context, line);
- if (!entry) return FALSE; /* ### */
- if (BM_ISHEADER(entry)) {
- if (under && (BM_ISFOLDED(entry) || entry->d.header.childCount == 0)) {
- return FALSE;
- }
- return TRUE;
- }
- return FALSE;
- }
-
-
- PUBLIC void
- BM_DoDrop(MWContext* context, int line, XP_Bool under)
- {
- BM_Entry* dest = BM_AtIndex(context, line);
- BM_Entry* tmp;
- BM_Entry* parent;
- BM_Entry* entry;
- CHKCONTEXTVOID(context);
- if (!dest) return;
- for (parent = dest ; parent ; parent = parent->parent) {
- if (BM_ISSELECTED(parent)) return;
- }
- tmp = BM_NewHeader("");
- if (!tmp) return;
- bm_start_batch(context);
- if (BM_ISHEADER(dest) && BM_IsDragEffectBox(context, line, under)) {
- parent = dest;
- dest = NULL;
- } else {
- parent = dest->parent;
- }
- BM_EachProperSelectedEntryDo(context, remove_to, tmp, NULL);
- entry = tmp->d.header.children;
- if (entry) {
- BM_ClearAllSelection(context, FALSE);
- while ((entry = tmp->d.header.children)) {
- BM_RemoveChildFromHeader(context, tmp, entry);
- BM_CLEARFLAG(entry, BM_ATTR_SELECTED);
- if (context->type == MWContextBookmarks) {
- if (dest) {
- bm_InsertItemAfter(context, dest, entry, FALSE);
- } else {
- BM_PrependChildToHeader(context, parent, entry);
- }
- } else {
- if (BM_ISALIAS(entry)) {
- bm_AddChildToHeaderSorted(context, parent, entry);
- } else {
- bm_AddChildToHeaderSorted(context, BM_GetRoot(context), entry);
- entry = bm_NewAlias(entry);
- bm_AddChildToHeaderSorted(context, parent, entry);
- }
- }
- if (!BM_ISHEADER(parent) || !BM_ISFOLDED(parent))
- BM_SelectItem(context, entry, FALSE, TRUE, TRUE);
- dest = entry;
- entry = tmp->d.header.children;
- }
- if (BM_ISHEADER(parent) && BM_ISFOLDED(parent))
- BM_SelectItem(context, parent, FALSE, TRUE, TRUE);
- BMFE_BookmarkMenuInvalid(context);
- bm_SyncCount(context);
- bm_refresh(context, 1, BM_LAST_CELL);
- }
- BM_FreeEntry(context, tmp);
- bm_end_batch(context);
- }
-
-
-
- typedef struct bm_goingaway_info {
- XP_Bool userasked;
- XP_Bool userconfirmed;
- BM_Entry* entry;
- int count;
- } bm_goingaway_info;
-
-
- static void
- bm_subtract_alias_for(MWContext* context, BM_Entry* entry, void* closure)
- {
- bm_goingaway_info* info = (bm_goingaway_info*) closure;
- if (BM_ISALIAS(entry) && entry->d.alias.original == info->entry) {
- info->count--;
- }
- }
-
-
- static void
- bm_delete_alias_for(MWContext* context, BM_Entry* entry, void* closure)
- {
- BM_Entry* base = (BM_Entry*) closure;
- if (BM_ISALIAS(entry) && entry->d.alias.original == base) {
- BM_RemoveChildFromHeader(context, entry->parent, entry);
- BM_FreeEntry(context, entry);
- }
- }
-
-
-
- static void
- bm_check_dangling_aliases(MWContext* context, BM_Entry* entry, void* closure)
- {
- BM_Frame* f = GETFRAME(context);
- bm_goingaway_info* info = (bm_goingaway_info*) closure;
- if (entry->flags & BM_ATTR_HASALIASES) {
- info->count = BM_CountAliases(context, entry);
- if (info->count) {
- /* Reduce the count by the number of aliases that we're going to
- delete. */
- info->entry = entry;
- BM_EachProperSelectedEntryDo(context, bm_subtract_alias_for, info, NULL);
- XP_ASSERT(info->count >= 0);
- if (info->count) {
- if (!info->userasked) {
- if (f->gSelectionCount < 0) bm_SyncSelection(context);
- if (f->gSelectionCount == 1) {
- char* buf = (char*) XP_ALLOC(512);
- if (buf) {
- XP_SPRINTF(buf,
- XP_GetString(XP_BKMKS_REMOVE_THIS_ITEMS_ALIASES), info->count);
- info->userconfirmed = FE_Confirm(context, buf);
- XP_FREE(buf);
- } else {
- info->userconfirmed =
- FE_Confirm
- (context,
- XP_GetString(XP_BKMKS_REMOVE_SOME_ITEMS_ALIASES) );
- }
- info->userasked = TRUE;
- }
- if (info->userconfirmed) {
- BM_EachEntryDo(context, bm_delete_alias_for, entry);
- }
- }
- }
- }
- }
- }
-
- static void
- bm_delete(MWContext* context)
- {
- BM_Entry* tmp;
- struct BM_Entry_Focus bmFocus;
- bm_goingaway_info info;
-
- tmp = BM_NewHeader("");
- XP_ASSERT(tmp);
- if (!tmp) return;
-
- XP_MEMSET(&info, 0, sizeof(info));
- BM_EachProperSelectedEntryDo(context, bm_check_dangling_aliases, &info,
- NULL);
- if (info.userasked && !info.userconfirmed) return;
-
- bmFocus.saveFocus = (BM_Entry*) NULL;
- bmFocus.foundSelection = FALSE;
- BM_EachProperSelectedEntryDo(context, remove_to, tmp, &bmFocus);
-
- BM_FreeEntry(context, tmp);
- bm_SyncCount(context);
-
- if (bmFocus.saveFocus == NULL)
- bmFocus.saveFocus = BM_GetRoot(context);
- if (bmFocus.saveFocus)
- BM_SETFLAG(bmFocus.saveFocus, BM_ATTR_SELECTED);
- bm_refresh(context, 1, BM_LAST_CELL);
- }
-
-
- static void
- bm_copy(MWContext* context)
- {
- char* block;
- int32 length;
-
- block = BM_ConvertSelectionsToBlock(context, TRUE, &length);
- BMFE_SetClipContents(context, (void*)block, length);
-
- XP_FREE(block);
- }
-
- static void
- bm_cut(MWContext* context)
- {
- bm_copy(context);
- bm_delete(context);
- }
-
-
- static void
- bm_paste(MWContext* context)
- {
- BM_Entry* firstSelected;
- char* buffer;
- int32 length;
-
- firstSelected = BM_FirstSelectedItem(context);
- buffer = (char*)BMFE_GetClipContents(context, &length);
- if (buffer)
- {
- BM_InsertBlockAt(context, buffer, firstSelected, TRUE, length);
- bm_SyncCount(context);
- bm_refresh(context, 1, BM_LAST_CELL);
- }
- }
-
- /* Insert a block of long-format entries */
- PUBLIC void
- BM_DropBlockL( MWContext *pContext, char *pData, BM_Entry *firstSelected )
- {
- int32 length;
-
- if( !firstSelected )
- {
- firstSelected = BM_FirstSelectedItem( pContext );
- }
-
- if( pData )
- {
- /* Length is stored at byte 0 as int32 */
- XP_MEMCPY( &length, pData, sizeof(int32) );
- pData += sizeof(int32);
-
- BM_InsertBlockAt( pContext, pData, firstSelected, TRUE, length );
- bm_SyncCount( pContext );
- bm_refresh( pContext, 1, BM_LAST_CELL );
- }
- }
-
- /* returns an integer index of the item in the visible tree */
- int32
- BM_GetIndex(MWContext* context, BM_Entry* item)
- {
- int32 count = 1;
-
- CHKCONTEXT(context);
-
- if (BM_GetRoot(context))
- return bm_GetIndexNum(BM_GetRoot(context), item, &count);
- else
- return 0;
- }
-
- /* returns an integer index of the item in the list and does not pay
- attention to the BM_ATTR_FOLDED value */
- int32
- BM_GetUnfoldedIndex(MWContext* context, BM_Entry* item)
- {
- int32 count = 1;
-
- BM_Entry* root = BM_GetRoot(context);
-
- CHKCONTEXT(context);
-
- if (root)
- return bm_GetUnfoldedIndexNum(root, item, &count);
- else
- return 0;
- }
-
- /* returns TRUE if the second argument is a direct
- descendent of the first argument.
- returns FALSE otherwise */
- PUBLIC XP_Bool
- BM_IsDescendent(MWContext* context, BM_Entry* parent, BM_Entry* possible_child)
- {
- int32 count = 1;
- CHKCONTEXT(context);
-
- if ( parent &&
- parent->type == BM_TYPE_HEADER &&
- bm_GetUnfoldedIndexNum(parent, possible_child, &count))
- return TRUE;
-
- return FALSE;
- }
-
-
- /* returns an integer depth of the item in the list starting at zero */
- PUBLIC int32
- BM_GetDepth(MWContext* context, BM_Entry* item)
- {
- CHKCONTEXT(context);
- if (BM_GetRoot(context))
- return bm_GetDepth(BM_GetRoot(context), item);
- else
- return 0;
- }
-
-
- /* returns the item at "count" visible indexes below "item" */
- static BM_Entry*
- bm_AtIndex(BM_Entry* item, int32* count)
- {
- XP_ASSERT(item);
- XP_ASSERT(item->type == BM_TYPE_HEADER);
-
- (*count)--;
-
- /* first check to see if parent is the node we are looking for */
- if (*count <= 0)
- return item;
-
- if (!BM_ISFOLDED(item))
- {
- BM_Entry* child;
-
- child = item->d.header.children;
- while (child)
- {
- if (child->type == BM_TYPE_HEADER)
- {
- BM_Entry* rv = NULL;
-
- rv = bm_AtIndex(child, count);
- if (rv)
- return rv;
- }
- else
- {
- (*count)--;
- if (*count <= 0)
- return child;
- }
- child = child->next;
- }
- }
- return NULL;
- }
-
- /* returns the object associated with the index returned by BM_GetIndex() */
- BM_Entry*
- BM_AtIndex(MWContext* context, int32 index)
- {
- BM_Frame* f = GETFRAME(context);
- static BM_Frame* last_f = NULL;
- static BM_Entry* last_item = NULL;
- static int32 last_index = -1;
-
- int32 count = index;
-
- CHKCONTEXT(context);
-
- /* only used the cached items if last_item is non-NULL and the
- requested index is one more than the last requested index */
- if (last_f == f && last_item && (index == (last_index + 1)))
- {
- /* if we're not a header
- or we're a header but folded,
- or we're a header but have no children,
- just go to the next item and set the local cache */
- if ( (last_item->type != BM_TYPE_HEADER) ||
- (last_item->flags & BM_ATTR_FOLDED) ||
- (! last_item->d.header.children))
- {
- last_item = last_item->next;
- if (last_item)
- {
- last_index = index;
- return last_item;
- }
- else
- {
- last_index = -1;
- return BM_AtIndex(context, index);
- }
- }
- else
- /* we're a header, we're unfolded, and we have children */
- {
- last_item = last_item->d.header.children;
- last_index = index;
- return last_item;
- }
- }
-
- if (BM_GetRoot(context) && index > 0)
- {
- last_item = bm_AtIndex(BM_GetRoot(context), &count);
- if (last_item)
- {
- last_f = f;
- last_index = index;
- return last_item;
- }
- }
- return NULL;
- }
-
- PRIVATE BM_Entry*
- bm_GetUnfoldedIndex(BM_Entry* parent, int32* index)
- {
- BM_Entry* child;
- BM_Entry* rv = 0;
-
- XP_ASSERT(parent);
- XP_ASSERT(parent->type == BM_TYPE_HEADER);
- child = parent->d.header.children;
-
- while (child)
- {
- *(index) -= 1;
-
- if (*index <= 0)
- return child;
-
- if (child->type == BM_TYPE_HEADER)
- {
- rv = bm_GetUnfoldedIndex(child, index);
-
- if (rv)
- return rv;
- }
- child = child->next;
- }
-
- return NULL;
- }
-
- /* returns the object associated with the index returned by BM_GetUnfoldedIndex() */
- PUBLIC BM_Entry*
- BM_AtUnfoldedIndex(MWContext* context, int32 index)
- {
- CHKCONTEXT(context);
- if (BM_GetRoot(context) && index > 0)
- return bm_GetUnfoldedIndex(BM_GetRoot(context), &index);
- else
- return NULL;
- }
-
-
- static void
- bm_fold_header_all(MWContext* context, BM_Entry* entry, XP_Bool fold,
- XP_Bool refresh)
- {
- if (BM_ISHEADER(entry)) {
- BM_FoldHeader(context, entry, fold, refresh, FALSE);
- for (entry = entry->d.header.children ; entry ; entry = entry->next) {
- bm_fold_header_all(context, entry, fold, refresh);
- }
- }
- }
-
-
- /* folds the header bm
- if fold is TRUE, the item becomes folded
- else the item is unfolded
- if refresh is TRUE, the FE is called to
- redraw necessary items
- if foldAll is TRUE, all headers appearing
- below bm in the tree are folded or unfolded
- according to "fold"
- */
- PUBLIC void
- BM_FoldHeader(MWContext* context, BM_Entry* bm, XP_Bool fold, XP_Bool refresh, XP_Bool foldAll)
- {
- BM_Frame* f = GETFRAME(context);
- int32 firstChangedCell = 0;
-
- CHKCONTEXTVOID(context);
- XP_ASSERT(bm);
- if (!bm) return;
-
- bm_CancelLastFind(context);
-
- f->max_depth = 0;
- if (foldAll)
- {
- bm_start_batch(context);
- bm_fold_header_all(context, bm, fold, refresh);
- bm_end_batch(context);
- return;
- }
- else
- {
-
- if (BM_ISFOLDED(bm) != fold)
- {
- int32 count;
- firstChangedCell = BM_GetIndex(context, bm);
-
- count = firstChangedCell;
-
- if (bm)
- {
- if (fold)
- {
- if (firstChangedCell != 0)
- BM_ClearAllChildSelection(context, bm, FALSE);
- BM_SETFLAG(bm, BM_ATTR_FOLDED);
- }
- else
- BM_CLEARFLAG(bm, BM_ATTR_FOLDED);
- }
-
- }
- }
-
- bm_SetModified(context, TRUE);
- bm_SyncCount(context);
-
- if (foldAll)
- firstChangedCell = MIN(1, firstChangedCell);
-
- if (refresh && (firstChangedCell != 0))
- bm_refresh(context, firstChangedCell, BM_LAST_CELL);
- }
-
-
-
- /* clears the selection state of all items in the tree
- if refresh is TRUE, the FE is called to redraw items
- which need to be redrawn
- */
- PUBLIC void
- BM_ClearAllSelection(MWContext* context, XP_Bool refresh)
- {
- BM_Frame* f = GETFRAME(context);
- int32 t = 1;
- CHKCONTEXTVOID(context);
-
- bm_ClearSelection(context, BM_GetRoot(context), refresh, &t);
- f->gSelectionCount = 0;
- f->gSelectionMask = 0;
- }
-
- /* Clears the selection state of all children of the item passed.
- if refresh is TRUE, the FE is called to redraw items
- which need to be redrawn
- */
- PUBLIC void
- BM_ClearAllChildSelection(MWContext* context, BM_Entry* at, XP_Bool refresh)
- {
- CHKCONTEXTVOID(context);
- if (!at) return;
- if (at->type != BM_TYPE_HEADER)
- return;
- at = at->d.header.children;
- while (at)
- {
- if (BM_ISSELECTED(at))
- BM_SelectItem(context, at, refresh, TRUE, FALSE);
- if ((at->type == BM_TYPE_HEADER) && (at->d.header.children))
- BM_ClearAllChildSelection(context, at->d.header.children, refresh);
- at = at->next;
- }
- }
-
- /* selects the item
- if refresh is TRUE, the FE is called to redraw the item
- if extend is TRUE, the item is added to the selection
- else the selection is cleared and the item becomes
- the selection
- if select is TRUE, the item is selected
- else it is deselected
-
- if extend is FALSE and select is FALSE, the selection
- becomes empty
- */
- PUBLIC void
- BM_SelectItem(MWContext* context, BM_Entry* item, XP_Bool refresh,
- XP_Bool extend, XP_Bool select)
- {
- BM_Frame* f = GETFRAME(context);
- CHKCONTEXTVOID(context);
- XP_ASSERT(item);
- if (!item) return;
- bm_start_batch(context);
- bm_CancelLastFind(context);
- if (!extend) {
- BM_ClearAllSelection(context, refresh);
- if (select) f->lastSelectedItem = item;
- }
- if (select) {
- if (!BM_ISSELECTED(item)) f->gSelectionCount++;
- f->gSelectionMask |= item->type;
- BM_SETFLAG(item, BM_ATTR_SELECTED);
- } else {
- BM_CLEARFLAG(item, BM_ATTR_SELECTED);
- f->gSelectionCount = -9999;
- }
- if (refresh) {
- int32 index = BM_GetIndex(context, item);
- if (index) bm_refresh(context, index, index);
- }
- if (!extend) BMFE_EditItem(context, item);
- bm_end_batch(context);
- }
-
-
-
- static BM_Entry*
- bm_validate_selected_item(MWContext* context, BM_Entry* item)
- {
- BM_Frame* f = GETFRAME(context);
- BM_Entry* result;
- for (; item ; item = item->next) {
- if (item == f->lastSelectedItem && BM_ISSELECTED(item)) return item;
- if (BM_ISHEADER(item) && !BM_ISFOLDED(item)) {
- result = bm_validate_selected_item(context, item->d.header.children);
- if (result) return result;
- }
- }
- return NULL;
- }
-
-
-
- static void
- bm_select_range(MWContext* context, BM_Entry* item, int32 min, int32 max,
- int32* cur)
- {
- for (; item ; item = item->next) {
- if (*cur >= min) {
- if (*cur > max) return;
- BM_SelectItem(context, item, FALSE, TRUE, TRUE);
- }
- (*cur)++;
- if (BM_ISHEADER(item) && !BM_ISFOLDED(item)) {
- bm_select_range(context, item->d.header.children, min, max, cur);
- }
- }
- }
-
-
-
- void
- BM_SelectRangeTo(MWContext* context, BM_Entry* item)
- {
- BM_Frame* f = GETFRAME(context);
- int32 min;
- int32 max;
- int32 cur;
- CHKCONTEXTVOID(context);
- XP_ASSERT(item);
- if (!item) return;
- /* First very carefully validate the lastSelectedItem pointer. That item
- might have been deleted or something, and the code in question may not
- have updated the lastSelectedItem pointer. So, we make sure that it still
- points to a valid item, and that the item is selected. */
- f->lastSelectedItem = bm_validate_selected_item(context,
- BM_GetRoot(context));
- if (!f->lastSelectedItem) {
- BM_SelectItem(context, item, TRUE, FALSE, TRUE);
- XP_ASSERT(f->lastSelectedItem == item); /* Not that we can do much if
- this fails...*/
- return;
- }
- min = BM_GetIndex(context, f->lastSelectedItem);
- max = BM_GetIndex(context, item);
- if (min < 1 || max < 1) return;
- if (min > max) {
- int32 tmp = min;
- min = max;
- max = tmp;
- }
- bm_start_batch(context);
- BM_ClearAllSelection(context, TRUE);
- cur = 1;
- bm_select_range(context, BM_GetRoot(context), min, max, &cur);
- XP_ASSERT(BM_ISSELECTED(item)); /* More sanity checking; not */
- XP_ASSERT(BM_ISSELECTED(f->lastSelectedItem)); /* really much we can do if
- these assertions fail.*/
- bm_refresh(context, min, max);
- bm_end_batch(context);
- }
-
-
- /* toggles the selected state of the item
- (see BM_SelectItem) */
- PUBLIC void
- BM_ToggleItem(MWContext* context, BM_Entry* item, XP_Bool refresh, XP_Bool extend)
- {
- CHKCONTEXTVOID(context);
- XP_ASSERT(item);
- if (!item) return;
-
- if (item->flags & BM_ATTR_SELECTED)
- BM_SelectItem(context, item, refresh, extend, FALSE);
- else
- BM_SelectItem(context, item, refresh, extend, TRUE);
- }
-
-
-
- static XP_Bool
- bm_ConfirmSave(MWContext* context)
- {
- /* XP_Bool doSave = FALSE;
- char* msg = "Save changes to %s?\n";
-
- sprintf(msg, f->gFile);
-
- if (BM_Modified(context))
- doSave = FE_SimpleConfirm(msg);
- return doSave;
- */
- return TRUE;
- }
-
-
- const char*
- BM_GetFileName(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- return f->gFile;
- }
-
-
-
- static XP_Bool
- bm_insert_bogus_aliases(XP_HashTable table, const void* key, void* value,
- void* closure)
- {
- MWContext* context = (MWContext*) closure;
- bm_alias_info* info = (bm_alias_info*) value;
- if (info->entry->parent == NULL) {
- /* This was an alias that was made up and inserted because we never could
- find the real entry for it. So, now we had better insert it into the
- tree. */
- if (context->type == MWContextBookmarks) {
- bm_AppendChildToHeader(context, BM_GetRoot(context), info->entry);
- } else {
- bm_AddChildToHeaderSorted(context, BM_GetRoot(context), info->entry);
- }
- }
- return TRUE;
- }
-
-
- /* Make sure the address book is sorted. */
- static void
- bm_resort_headers(MWContext* context, BM_Entry* header)
- {
- XP_Bool needssort;
- BM_Entry* entry;
- BM_Entry* prev;
- for ( ; header ; header = header->next) {
- if (BM_ISHEADER(header)) {
- prev = NULL;
- needssort = FALSE;
- for (entry = header->d.header.children ; entry ; entry = entry->next) {
- if (BM_ISHEADER(entry)) bm_resort_headers(context, entry);
- if (prev && bm_SortAddressBook(prev, entry) > 0) {
- needssort = TRUE;
- }
- prev = entry;
- }
- if (needssort) {
- BM_SelectItem(context, header, FALSE, FALSE, TRUE);
- bm_SortSelected(context, BM_Sort_Name);
- }
- }
- }
- }
-
-
- /* read bmlist file from disk
- pass in a file url */
- PUBLIC void
- BM_ReadBookmarksFromDisk(MWContext* context, const char* filename,
- const char* relative_url)
- {
- BM_Frame* f = GETFRAME(context);
- XP_File fp;
- char* buffer;
- UndoState* undo;
-
- CHKCONTEXTVOID(context);
-
- undo = f->undo;
- if (BM_Modified(context)) {
- if (!bm_ConfirmSave(context)) return;
- if (BM_SaveBookmarks(context, f->gFile) < 0) return;
- }
- if (f->gBookmarks) BM_FreeEntry(context, f->gBookmarks);
- f->gBookmarks = NULL;
-
- buffer = (char*) XP_ALLOC(READ_BUFFER_SIZE);
- if (!buffer) return;
-
- /* don't kill ourselves */
- if (f->gFile != filename)
- StrAllocCopy(f->gFile, filename);
-
- XP_ASSERT(f->gFile != NULL);
-
-
- if (XP_Stat(filename, &(f->laststat), xpBookmarks) != 0) {
- XP_MEMSET(&(f->laststat), 0, sizeof(f->laststat));
- }
-
- fp = XP_FileOpen(filename, xpBookmarks, XP_FILE_READ);
-
- if (!fp) {
- XP_FREE(buffer);
- return;
- }
-
- /* read in the first line */
- XP_FileReadLine(buffer, READ_BUFFER_SIZE, fp);
-
- /* DONT REQUIRE THE COOKIE FOR NOW
- *
- * if(XP_STRNCMP(buffer, BMLIST_COOKIE, strlen(BMLIST_COOKIE)
- && XP_STRNCMP(buffer, BM_ADDR_LIST_COOKIE, strlen(BM_ADDR_LIST_COOKIE))
- * {
- * TRACEMSG(("ERROR! - Hotlist cookie not found in bmlist file"));
- * XP_FREE(buffer);
- * return;
- * }
- */
-
- f->undo = NULL; /* No need to log all this stuff... */
- bm_start_batch(context);
- bm_refresh(context, 1, BM_LAST_CELL);
-
- bm_clear_alias_info(context);
-
- /* gBookmarks shouldn't exist yet! */
- bm_ReadFromHTML(context, fp, NULL, buffer, relative_url);
- bm_SyncCount(context);
-
- XP_FileClose(fp);
-
- XP_Maphash(f->aliasTable, bm_insert_bogus_aliases, context);
-
- if (context->type == MWContextAddressBook) {
- bm_resort_headers(context, BM_GetRoot(context));
- }
-
- bm_SetModified(context, FALSE);
-
- XP_FREE(buffer);
-
- bm_end_batch(context);
- f->undo = undo;
- UNDO_DiscardAll(undo);
- }
-
- PUBLIC int32
- BM_SaveBookmarks(MWContext* context, const char* filename)
- {
- BM_Frame* f = GETFRAME(context);
- XP_File fp = NULL;
- const char* bm_list_name;
- XP_FileType tmptype;
- char* tmpname = NULL;
- XP_StatStruct curstat;
- XP_Bool defaultFile;
- BM_SortType enSortType = f->enSortType;
- /* recognize if we're saving the current bookmarks file */
- defaultFile = (filename == NULL || (f->gFile && XP_STRCMP(filename, f->gFile) == 0));
-
- CHKCONTEXT(context);
-
- if (filename == NULL) {
- filename = f->gFile;
- if (filename == NULL) return -1; /* ### */
- if (XP_Stat(filename, &curstat, xpBookmarks) != 0) {
- /* The stat failed. Treat it as if the stat gave the same thing as last
- time (i.e., make sure to *not* whine about the file changing from us;
- most likely, the user just removed it.) */
- XP_MEMCPY(&curstat, &(f->laststat), sizeof(curstat));
- }
- if (curstat.st_mtime != f->laststat.st_mtime ||
- curstat.st_size != f->laststat.st_size) {
- if (f->gBookmarksModified) {
- if (FE_Confirm(context,
- XP_GetString(context->type == MWContextAddressBook ?
- XP_BKMKS_ADDRESSBOOK_CONFLICT :
- XP_BKMKS_BOOKMARKS_CONFLICT))) {
- f->gBookmarksModified = FALSE; /* Prevent BM_ReadBookmarksFromDisk
- from calling us back again. */
- BM_ReadBookmarksFromDisk(context, filename, NULL);
- return 0;
- }
- } else {
- FE_Alert(context,
- XP_GetString(context->type == MWContextAddressBook ?
- XP_BKMKS_ADDRESSBOOK_CHANGED :
- XP_BKMKS_BOOKMARKS_CHANGED));
- BM_ReadBookmarksFromDisk(context, filename, NULL);
- return 0;
- }
- } else {
- if (!f->gBookmarksModified) return 0; /* No changes need to be saved. */
- }
- }
-
- /* Save the natural (user arranged) sort */
- if (defaultFile && (enSortType != BM_Sort_Natural)) {
- bm_SortSilent( context, BM_Sort_Natural );
- }
-
- bm_list_name = FE_UsersFullName();
- if (!bm_list_name) bm_list_name = FE_UsersMailAddress();
-
- tmpname = FE_GetTempFileFor(NULL, filename, xpBookmarks, &tmptype);
- if (!tmpname || tmpname[0] == 0) goto FAIL;
-
- fp = XP_FileOpen(tmpname, tmptype, XP_FILE_WRITE);
-
- if (!fp) goto FAIL;
-
- /* write cookie */
- if (context->type == MWContextBookmarks) {
- if (bm_write_ok(BMLIST_COOKIE, -1, fp) < 0) goto FAIL;
- } else {
- if (bm_write_ok(BM_ADDR_LIST_COOKIE, -1, fp) < 0) goto FAIL;
- }
- if (bm_write_ok(LINEBREAK, LINEBREAK_LEN, fp) < 0) goto FAIL;
-
- if (bm_write_ok(XP_GetString(XP_BKMKS_AUTOGENERATED_FILE), -1, fp) < 0) {
- goto FAIL;
- }
- if (bm_write_ok(LINEBREAK, LINEBREAK_LEN, fp) < 0) goto FAIL;
- if (bm_write_ok(XP_GetString(XP_BKMKS_READ_AND_OVERWRITE), -1, fp) < 0) goto FAIL;
- if (bm_write_ok(LINEBREAK, LINEBREAK_LEN, fp) < 0) goto FAIL;
- if (bm_write_ok(XP_GetString(XP_BKMKS_DO_NOT_EDIT), -1, fp) < 0) goto FAIL;
- if (bm_write_ok(LINEBREAK, LINEBREAK_LEN, fp) < 0) goto FAIL;
-
- if(context->type == MWContextBookmarks) {
- if(bm_list_name) {
- XP_FilePrintf(fp, XP_GetString(XP_BKMKS_SOMEONE_S_BOOKMARKS),
- "<TITLE>",
- bm_list_name,
- "</TITLE>" LINEBREAK);
- XP_FilePrintf(fp, XP_GetString(XP_BKMKS_SOMEONE_S_BOOKMARKS),
- "<H1>",
- bm_list_name,
- "</H1>\n" LINEBREAK);
- } else {
- XP_FilePrintf(fp, XP_GetString(XP_BKMKS_PERSONAL_BOOKMARKS),
- "<TITLE>",
- "</TITLE>" LINEBREAK);
- XP_FilePrintf(fp, XP_GetString(XP_BKMKS_PERSONAL_BOOKMARKS),
- "<H1>",
- "</H1>\n" LINEBREAK);
- }
- } else {
- if(bm_list_name) {
- XP_FilePrintf(fp, XP_GetString(XP_BKMKS_SOMEONE_S_ADDRESSBOOK),
- "<TITLE>",
- bm_list_name,
- "</TITLE>" LINEBREAK);
- XP_FilePrintf(fp, XP_GetString(XP_BKMKS_SOMEONE_S_ADDRESSBOOK),
- "<H1>",
- bm_list_name,
- "</H1>\n" LINEBREAK);
- } else {
- XP_FilePrintf(fp, XP_GetString(XP_BKMKS_PERSONAL_ADDRESSBOOK),
- "<TITLE>",
- "</TITLE>" LINEBREAK);
- XP_FilePrintf(fp, XP_GetString(XP_BKMKS_PERSONAL_ADDRESSBOOK),
- "<H1>",
- "</H1>\n" LINEBREAK);
- }
- }
-
- bm_clear_alias_info(context);
-
- if (BM_GetRoot(context)) {
- if (bm_WriteAsHTML(context, fp, BM_GetRoot(context), 0, FALSE) < 0) {
- goto FAIL;
- }
- } else {
- XP_TRACE(("No bmlist to write!"));
- }
-
- if (XP_FileClose(fp) != 0) {
- fp = NULL;
- goto FAIL;
- }
- fp = NULL;
- XP_FileRename(tmpname, tmptype, filename, xpBookmarks);
- XP_FREE(tmpname);
- tmpname = NULL;
-
- #ifdef XP_UNIX
- /* If we write the bookmarks with at different uid or gid
- * than what it had, try to change it back.
- * Fix for 67572, bookmarks.html get wiped out.
- */
- if (curstat.st_uid != getuid()
- || curstat.st_gid != getgid()) {
- chown (filename, curstat.st_uid, curstat.st_gid);
- }
- #endif /* XP_UNIX */
-
- /* only update global mod date if we saved the current bookmk file */
- if (defaultFile) {
-
- if (XP_Stat(filename, &(f->laststat), xpBookmarks) != 0) {
- XP_MEMSET(&(f->laststat), 0, sizeof(f->laststat));
- }
-
- bm_SetModified(context, FALSE);
-
- /* Reset the previous sort order */
- if (enSortType != BM_Sort_Natural) {
- bm_SortSilent( context, enSortType );
- }
-
- }
-
- if (context->type == MWContextBookmarks)
- f->errorSavingBookmarks = FALSE;
-
- return 1;
-
- FAIL:
- if (fp) XP_FileClose(fp);
- if (tmpname) {
- XP_FileRemove(tmpname, tmptype);
- XP_FREE(tmpname);
- tmpname = NULL;
- }
-
- if (context->type == MWContextAddressBook) {
- FE_Alert(context, XP_GetString(XP_BKMKS_CANT_WRITE_ADDRESSBOOK));
- }
- else {
- if (!f->errorSavingBookmarks) {
- FE_Alert(context, XP_GetString(XP_BKMKS_CANT_WRITE_BOOKMARKS));
- f->errorSavingBookmarks = TRUE;
- }
- }
-
- return -1;
- }
-
-
- /* returns the first selected item
- if parent is selected, parent is returned,
- otherwise the first selected child is returned
- if there is no selected item following parent,
- NULL is returned */
- PRIVATE BM_Entry*
- bm_FirstSelectedItem_1(BM_Entry* parent)
- {
- BM_Entry* child;
-
- XP_ASSERT(parent);
- XP_ASSERT(BM_ISHEADER(parent));
-
- if (BM_ISSELECTED(parent)) return parent;
-
- child = parent->d.header.children;
- while (child)
- {
- if (child->flags & BM_ATTR_SELECTED)
- return child;
- if (child->type == BM_TYPE_HEADER)
- {
- BM_Entry* rv;
- rv = bm_FirstSelectedItem_1(child);
- if (rv)
- return rv;
- }
- child = child->next;
- }
- return NULL;
- }
-
- PUBLIC BM_Entry*
- BM_FirstSelectedItem(MWContext* context)
- {
- CHKCONTEXT(context);
- return bm_FirstSelectedItem_1(BM_GetRoot(context));
- }
-
- static void
- bm_InsertBySelection(MWContext* context, BM_Entry* firstSelected,
- BM_Entry* newItem)
- {
- BM_Frame* f = GETFRAME(context);
- CHKCONTEXTVOID(context);
- XP_ASSERT(firstSelected);
- if (!firstSelected) firstSelected = BM_GetRoot(context);
-
- /* If we've selected the root node, then make sure it's not folded, so that
- we will be sure to put our new item inside the root, where it belongs. */
-
- if (firstSelected == BM_GetRoot(context) && BM_ISFOLDED(firstSelected)) {
- BM_FoldHeader(context, firstSelected, FALSE, TRUE, FALSE);
- }
-
- f->max_depth = 0;
-
- if (context->type == MWContextAddressBook && !BM_ISALIAS(newItem)) {
- bm_AddChildToHeaderSorted(context, BM_GetRoot(context), newItem);
- } else {
- /* insert into header if it's open, else after it */
- if (BM_ISHEADER(firstSelected) && !BM_ISFOLDED(firstSelected)) {
- if (context->type == MWContextBookmarks) {
- BM_PrependChildToHeader(context, firstSelected, newItem);
- } else {
- bm_AddChildToHeaderSorted(context, firstSelected, newItem);
- }
- } else {
- if (context->type == MWContextBookmarks) {
- bm_InsertItemAfter(context, firstSelected, newItem, TRUE);
- } else {
- bm_AddChildToHeaderSorted(context, firstSelected->parent, newItem);
- }
- }
- }
- }
-
- static void
- bm_BeginEditNewHeader(MWContext* context)
- {
- BM_Entry* header;
- BM_Entry* firstSelected;
- int32 index;
-
-
- firstSelected = BM_FirstSelectedItem(context);
- if (firstSelected)
- index = BM_GetIndex(context, firstSelected);
- else
- {
- firstSelected = BM_GetRoot(context);
- index = 1;
- }
-
- header = BM_NewHeader(XP_GetString(XP_BKMKS_NEW_HEADER));
-
- BM_SETFLAG(header, BM_ATTR_ISNEW);
-
- bm_InsertBySelection(context, firstSelected, header);
- BM_SelectItem(context, header, TRUE, FALSE, TRUE);
- bm_SyncCount(context);
- bm_refresh(context,
- context->type == MWContextBookmarks ? index + 1 : 1,
- BM_LAST_CELL);
- BMFE_OpenBookmarksWindow(context);
- BMFE_EditItem(context, header);
- }
-
- static void
- bm_BeginEditNewUrl(MWContext* context)
- {
- BM_Entry* url;
- BM_Entry* firstSelected;
- int32 index;
-
- firstSelected = BM_FirstSelectedItem(context);
- if (firstSelected)
- index = BM_GetIndex(context, firstSelected);
- else
- {
- firstSelected = BM_GetRoot(context);
- index = 1;
- }
-
- if (context->type == MWContextBookmarks) {
- url = BM_NewUrl(XP_GetString(XP_BKMKS_NEW_BOOKMARK), NULL, NULL, 0);
- } else {
- url = bm_NewAddress("", "");
- }
- if (!url) return;
- BM_SETFLAG(url, BM_ATTR_ISNEW);
- if (context->type == MWContextBookmarks) {
- bm_InsertBySelection(context, firstSelected, url);
- } else {
- bm_AddChildToHeaderSorted(context, BM_GetRoot(context), url);
- }
- BM_SelectItem(context, url, TRUE, FALSE, TRUE);
- bm_SyncCount(context);
- bm_refresh(context,
- context->type == MWContextBookmarks ? index + 1 : 1,
- BM_LAST_CELL);
- BMFE_OpenBookmarksWindow(context);
- BMFE_EditItem(context, url);
- }
-
- PUBLIC void
- BM_GotoBookmark(MWContext* context, BM_Entry* item)
- {
- char* url = NULL;
- char* target = NULL;
-
- CHKCONTEXTVOID(context);
-
- XP_ASSERT(item);
- if (!item) return;
-
- if (item->type == BM_TYPE_ALIAS)
- {
- XP_ASSERT(BM_ISURL(item->d.alias.original));
- if (BM_ISURL(item->d.alias.original)) {
- url = item->d.alias.original->d.url.address;
- target = item->d.alias.original->d.url.target;
- }
- }
- else if (item->type == BM_TYPE_URL)
- {
- url = item->d.url.address;
- target = item->d.url.target;
- }
-
- if (url)
- BMFE_GotoBookmark(context, url, target);
- }
-
- static void
- bm_BeginFindBookmark(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- if (!f->gFindInfo) {
- f->gFindInfo = XP_NEW_ZAP(BM_FindInfo);
- if (!f->gFindInfo) return;
- if (context->type == MWContextAddressBook) {
- f->gFindInfo->checkNickname = TRUE;
- }
- f->gFindInfo->checkName = TRUE;
- f->gFindInfo->checkLocation = TRUE;
- f->gFindInfo->checkDescription = TRUE;
- }
- f->gFindInfo->lastEntry = NULL;
- f->gTemporary = BMFE_OpenFindWindow(context, f->gFindInfo);
- }
-
-
- PRIVATE void
- bm_SelectAliases(MWContext* context, BM_Entry* at, BM_Entry* forEntry)
- {
- BM_Entry* head;
- for ( ; at ; at = at->next) {
- if (at->type == BM_TYPE_HEADER) {
- bm_SelectAliases(context, at->d.header.children, forEntry);
- } else if (BM_ISALIAS(at) && at->d.alias.original == forEntry) {
- BM_SelectItem(context, at, TRUE, TRUE, TRUE);
- for (head = at->parent ; head ; head = head->parent) {
- if (BM_ISFOLDED(head)) {
- BM_FoldHeader(context, head, FALSE, TRUE, FALSE);
- }
- }
- }
- }
- }
-
- PUBLIC void
- BM_SelectAliases(MWContext* context, BM_Entry* forEntry)
- {
- CHKCONTEXTVOID(context);
- XP_ASSERT(forEntry);
- if (forEntry) {
- bm_start_batch(context);
- bm_SelectAliases(context, BM_GetRoot(context), forEntry);
- bm_end_batch(context);
- BMFE_ScrollIntoView(context, forEntry);
- }
- }
-
- static void
- bm_CloseLastFind_1(MWContext* context, BM_Entry* entry, XP_Bool closeit)
- {
- for ( ; entry ; entry = entry->next) {
- if (BM_ISHEADER(entry)) {
- if (entry->flags & BM_ATTR_FINDAFF) {
- if (closeit) BM_FoldHeader(context, entry, TRUE, TRUE, FALSE);
- BM_CLEARFLAG(entry, BM_ATTR_FINDAFF);
- }
- bm_CloseLastFind_1(context, entry->d.header.children, closeit);
- }
- }
- }
-
-
- /* Close any headers that we may have opened last time we did a find. */
- static void
- bm_CloseLastFind(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- if (f->unfoldedForFind) {
- f->unfoldedForFind = FALSE; /* Do this first, to not confuse
- BM_FoldHeader(). */
- bm_CloseLastFind_1(context, BM_GetRoot(context), TRUE);
- }
- }
-
- /* Forget about any headers that were opened last time we did a find; leave
- things the way they are now. */
- static void
- bm_CancelLastFind(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- if (f->unfoldedForFind) {
- f->unfoldedForFind = FALSE;
- bm_CloseLastFind_1(context, BM_GetRoot(context), FALSE);
- }
- }
-
- static void
- bm_OpenNewFind(MWContext* context, BM_Entry* entry)
- {
- BM_Frame* f = GETFRAME(context);
- BM_Entry* head;
- XP_Bool found = FALSE;
- if (!entry) return;
- bm_CloseLastFind(context);
- for (head = entry->parent ; head ; head = head->parent) {
- if (BM_ISFOLDED(head)) {
- BM_FoldHeader(context, head, FALSE, TRUE, FALSE);
- BM_SETFLAG(head, BM_ATTR_FINDAFF);
- found = TRUE;
- }
- }
- f->unfoldedForFind = found; /* Must set last, to not confuse
- BM_FoldHeader. */
- }
-
-
- void
- BM_DoFindBookmark(MWContext* context, BM_FindInfo* findInfo)
- {
- BM_Frame* f = GETFRAME(context);
- BM_Entry* found = NULL;
- BM_Entry* startAt = NULL;
- XP_Bool unfoldedForFind;
-
- /* If no find string is specified, return. */
- if (findInfo->textToFind == NULL)
- return;
-
- bm_CloseLastFind(context);
-
- if (findInfo->lastEntry) {
- startAt = bm_GetNextSpanningWrapping(context, findInfo->lastEntry);
- } else {
- startAt = BM_GetRoot(context);
- }
- found = bm_DoFindBookmark_1(context, startAt, findInfo);
-
- if (found) {
- bm_CloseLastFind(context);
- bm_OpenNewFind(context, found);
- unfoldedForFind = f->unfoldedForFind;
- f->unfoldedForFind = FALSE; /* Don't confuse BM_SelectItem */
- BM_SelectItem(context, found, TRUE, FALSE, TRUE);
- bm_flush_updates(context);
- BMFE_ScrollIntoView(context, found);
- f->unfoldedForFind = unfoldedForFind;
- } else {
- FE_Alert(context, XP_GetString(XP_BKMKS_NOT_FOUND));
- }
- findInfo->lastEntry = found;
- }
-
-
- static void
- bm_parse_mailto(const char* url, char** name, char** addr)
- {
- char* ptr;
- char* buf;
- int32 L;
- if (name) *name = NULL;
- if (addr) *addr = NULL;
- if (strncasecomp(url, "mailto:?to=", 11) != 0) return;
- url += 11;
- ptr = XP_STRCHR(url, '&');
- L = (ptr ? (ptr - url) : XP_STRLEN(url));
- buf = (char *) XP_ALLOC(L+1);
- if (!buf) return;
- XP_MEMCPY (buf, url, L);
- buf[L] = 0;
- buf = NET_UnEscape(buf);
-
- #if 0
- MSG_ParseRFC822Addresses(buf, name, addr);
- #else
- /* We need to do it this way to get msg_quote_phrase_or_addr() to be
- called on the names. Perhaps that function should just be exported...
- */
- #ifdef MOZ_MAIL_NEWS
- if (name) *name = MSG_ExtractRFC822AddressNames (buf);
- if (addr) *addr = MSG_ExtractRFC822AddressMailboxes (buf);
- #endif /* MOZ_MAIL_NEWS */
- #endif
-
- XP_FREE(buf);
- }
-
- BM_Entry*
- BM_FindAddress(MWContext* context, const char* url)
- {
- char* address;
- BM_Entry* result = NULL;
- BM_Entry* entry;
- CHKCONTEXT(context);
- XP_ASSERT(url);
- if (!url) return NULL;
- bm_parse_mailto(url, NULL, &address);
- if (!address) return NULL;
-
- /* Takes advantage of the fact that addressbook always has all address
- entries as children of the root header. */
- for (entry = BM_GetRoot(context)->d.header.children;
- entry;
- entry = entry->next) {
- if (BM_ISADDRESS(entry) &&
- XP_STRCMP(entry->d.address.address, address) == 0) {
- result = entry;
- break;
- }
- }
- XP_FREE(address);
- return result;
- }
-
-
- void
- BM_EditAddress(MWContext* context, const char* url)
- {
- BM_Entry* entry;
- CHKCONTEXTVOID(context);
- XP_ASSERT(url);
- if (!url) return;
- bm_start_batch(context);
- entry = BM_FindAddress(context, url);
- if (!entry) {
- char* name;
- char* address;
- bm_parse_mailto(url, &name, &address); /* Parsing a second time. Oh,
- well. ### */
- if (!name) name = XP_STRDUP("");
- if (!address) address = XP_STRDUP("");
- if (!name || !address) goto FAIL;
-
- entry = bm_NewAddress(name, address);
- XP_FREE(name);
- XP_FREE(address);
- if (!entry) goto FAIL;
- BM_SETFLAG(entry, BM_ATTR_ISNEW);
- bm_AddChildToHeaderSorted(context, BM_GetRoot(context), entry);
- BM_SelectItem(context, entry, TRUE, FALSE, TRUE);
- bm_SyncCount(context);
- bm_refresh(context, 1, BM_LAST_CELL);
- }
- BMFE_OpenBookmarksWindow(context);
- BMFE_EditItem(context, entry);
- FAIL:
- bm_end_batch(context);
- }
-
-
-
-
- /*
- * Utilities to fuss with bookmarks in a drag and drop evnironment
- *
- * There are two user visible functions in this file:
- *
- * Allocate and return a string that contains the text representation of
- * a list of bookmarks entries (including headers and their contents).
- * The caller is responsible for freeing the string. The total length of
- * the block that was allocated is returned in lTotalLen. List is the
- * list of pointers to bookmarks items that are selected, iCount is the
- * length of that list.
- * This function has two modes of operation, a short mode and a long mode.
- * If bLongFormat == FALSE the returned block just has URLs separated by
- * \n's. If bLongFormat == TRUE all of the information needed to recreate
- * the bookmarks item is included
- *
-
- PUBLIC char *
- BM_ConvertSelectionsToBlock(BM_Entry ** list,
- int iCount,
- int bLongFormat,
- int32 * lTotalLen);
- *
- * ------------------------
- *
- * Take a block of memory formatted by BM_ConvertSelectionsToBlock and insert
- * the items it represents into the bookmarks following 'item'. If item is
- * NULL insert at the beginning of the bookmarks. bLongFormat has the same
- * meaning as in BM_ConvertSelectionsToBlock(). lTotalLen should be the
- * length of the block of memory --- I'm not sure if this is necessary
- * because on Windows at least the value we get back is meaningless, so
- * this function just ignores it.
- *
- PUBLIC void
- BM_InsertBlockAt(char * pOriginalBlock,
- BM_Entry * item,
- int bLongFormat,
- int32 lTotalLen);
- *
- */
-
-
-
- #define TEXT_INDENT 3
-
- /*
- * Measure a boring URL bookmarks entry and return the length in bytes
- *
- * Short format:
- * " item->address\n"
- * where there are nIndent number of spaces before the item
- *
- * Long format:
- * uint16 type
- * char item->name\n
- * char item->address\n
- * time_t addition_date
- * time_t last_visit_date
- * time_t last_modified_date
- * char item->description\0
- *
- * The item->description field is *NOT* \n terminated since it might
- * be a multi-line string and is therefore \0 terminated
- */
- PRIVATE int32
- bm_measure_URL(BM_Entry* item, XP_Bool bLongFormat, int nIndent)
- {
- int32 iSpace = 0;
-
- if (!item)
- return 0;
-
- XP_ASSERT(BM_ISURL(item));
-
- /* NO. We cannot check for ISSELECTED here. We could be called
- * by bm_measure_Header which was selected although we by
- * ourselves are not selected.
- *
- * if (! BM_ISSELECTED(item))
- * return 0;
- */
-
- if (bLongFormat)
- {
- iSpace += sizeof(item->type) +
- sizeof(item->addition_date) +
- sizeof(item->d.url.last_visit) +
- sizeof(item->d.url.last_modified);
-
- if (item->name)
- iSpace += XP_STRLEN(item->name);
- iSpace++; /* +1 for '\n' */
- if (item->description)
- iSpace += XP_STRLEN(item->description);
- iSpace++; /* +1 for '\0' */
- }
- else
- {
- /* space indentation and '\n' terminator */
- iSpace = nIndent;
- }
-
- /* the address appears in both formats */
- if (item->d.url.address)
- iSpace += (XP_STRLEN(item->d.url.address) + 1); /* +1 for '\n' */
-
- return (iSpace);
- }
-
- PRIVATE int32
- bm_measure_Alias(BM_Entry* item, XP_Bool bLongFormat, int nIndent)
- {
- int32 iSpace = 0;
-
- XP_ASSERT(BM_ISALIAS(item));
-
- if (bLongFormat)
- {
- iSpace += sizeof(item->type);
- }
- return (iSpace);
- }
-
- /*
- * Measure a separator entry and return the length in bytes
- *
- * Short format:
- * " -------------\0"
- * where there are nIndent number of spaces before the 13 -'s
- *
- * Long format:
- * uint16 type
- *
- */
- PRIVATE int32
- bm_measure_Separator(BM_Entry* item, XP_Bool bLongFormat, int nIndent)
- {
- int32 iSpace = 0;
-
- if (!item)
- return 0;
-
- XP_ASSERT(BM_ISSEPARATOR(item));
-
- if (bLongFormat)
- {
- iSpace += sizeof(item->type);
- }
- else
- {
- /* space indentation and '\n' terminator */
- iSpace = nIndent;
- iSpace += 13;
- iSpace ++ /* for '\n' */;
- }
-
- return (iSpace);
- }
-
- /*
- * Measure a header entry and all its children
- *
- * Short format:
- * " item->name\n"
- * " child1->address\n"
- * " child2->address\n"
- * where there are nIndent number of spaces before the item and
- * TEXT_INDENT spaces between levels
- *
- * Long format:
- * uint16 type
- * char item->name\n
- * time_t addition_date
- * uint32 number of children
- * char item->description\0
- *
- * The item->description field is *NOT* \n terminated since it might
- * be a multi-line string and is therefore \0 terminated. Note that
- * the address field is *NOT* written for headers since its it meaningless
- */
- PRIVATE int32
- bm_measure_Header(BM_Entry* item, XP_Bool bLongFormat, int nIndent)
- {
- int32 iSpace = 0;
- BM_Entry* child = NULL;
-
- if (!item)
- return 0;
-
- XP_ASSERT(BM_ISHEADER(item));
-
- /* if the header is selected, count it as well */
- if (bLongFormat)
- {
- iSpace += sizeof(item->type) +
- sizeof(item->addition_date) +
- sizeof(item->d.header.childCount);
-
- if (item->description)
- iSpace += XP_STRLEN(item->description);
- iSpace++; /* for \0 */
- }
- else
- {
- /* space indentation and '\n' terminator */
- iSpace = nIndent;
- }
-
- /* the name appears in both formats */
- if (item->name)
- iSpace += XP_STRLEN(item->name);
- iSpace ++; /* for \n terminator */
-
- /* measure the amount of space taken up by this item's children */
- child = item->d.header.children;
- while (child)
- {
- switch (child->type)
- {
- case BM_TYPE_URL:
- iSpace += bm_measure_URL(child, bLongFormat, nIndent + TEXT_INDENT);
- break;
- case BM_TYPE_ALIAS:
- iSpace += bm_measure_Alias(child, bLongFormat, nIndent + TEXT_INDENT);
- break;
- case BM_TYPE_HEADER:
- iSpace += bm_measure_Header(child, bLongFormat, nIndent + TEXT_INDENT);
- break;
- case BM_TYPE_SEPARATOR:
- iSpace += bm_measure_Separator(child, bLongFormat, nIndent + TEXT_INDENT);
- break;
- default:
- break;
- }
- child = child->next;
- }
-
- return iSpace;
- }
-
- /*
- * Write out a separator bookmarks entry.
- */
- PRIVATE char*
- bm_write_Separator(char* buffer, BM_Entry* item, XP_Bool bLongFormat, int nIndent)
- {
- int32 iLen;
- BM_Type type;
-
- if (!item || !buffer)
- return buffer;
-
- XP_ASSERT(BM_ISSEPARATOR(item));
-
- if (bLongFormat)
- {
- /* copy the type */
- type = item->type;
- iLen = sizeof(BM_Type);
- XP_MEMCPY(buffer, &type, iLen);
- buffer += iLen;
- }
- else
- {
- XP_MEMSET(buffer, ' ', nIndent);
- buffer += nIndent;
- XP_MEMSET(buffer, '-', 13);
- buffer += 13;
- *buffer++ = '\0';
- }
-
- return buffer;
- }
-
- /*
- * Write out a boring URL bookmarks entry. See comment at the top of
- * bm_measure_URL for the format used. Assume we start writing at
- * the start of the buffer passed in. Return a pointer to where the
- * buffer ends when we get done.
- */
- PRIVATE char*
- bm_write_URL(char* buffer, BM_Entry* item, XP_Bool bLongFormat, int nIndent)
- {
- int32 iLen;
- BM_Date lVal;
- BM_Type type;
-
- if (!item || !buffer)
- return buffer;
-
- XP_ASSERT(BM_ISURL(item) || BM_ISALIAS(item));
-
- if (bLongFormat)
- {
- /* copy the type */
- type = item->type;
- iLen = sizeof(BM_Type);
- XP_MEMCPY(buffer, &type, iLen);
- buffer += iLen;
-
- if (BM_ISALIAS(item))
- return buffer;
-
- /* copy the name */
- if (item->name)
- {
- iLen = XP_STRLEN(item->name);
- XP_MEMCPY(buffer, item->name, iLen);
- buffer += iLen;
- }
- /* put the \n terminator on */
- *buffer++ = '\n';
-
- /* copy the address */
- if (item->d.url.address)
- {
- iLen = XP_STRLEN(item->d.url.address);
- XP_MEMCPY(buffer, item->d.url.address, iLen);
- buffer += iLen;
- }
- /* put the \n terminator on */
- *buffer++ = '\n';
-
- /* addition date */
- lVal = item->addition_date;
- iLen = sizeof(BM_Date);
- XP_MEMCPY(buffer, &lVal, iLen);
- buffer += iLen;
-
- /* last visit date */
- lVal = item->d.url.last_visit;
- iLen = sizeof(BM_Date);
- XP_MEMCPY(buffer, &lVal, iLen);
- buffer += iLen;
-
- /* last modified date */
- lVal = item->d.url.last_modified;
- iLen = sizeof(BM_Date);
- XP_MEMCPY(buffer, &lVal, iLen);
- buffer += iLen;
-
- /* copy the description */
- if (item->description)
- {
- iLen = XP_STRLEN(item->description);
- XP_MEMCPY(buffer, item->description, iLen);
- buffer += iLen;
- }
- /* put the \n terminator on */
- *buffer++ = '\0';
-
- }
- else if (BM_ISURL(item))
- {
- XP_MEMSET(buffer, ' ', nIndent);
- buffer += nIndent;
-
- if(item->d.url.address)
- {
- XP_STRCPY(buffer, item->d.url.address);
- buffer += XP_STRLEN(item->d.url.address);
- }
- *buffer++ = '\n';
- }
-
- return buffer;
- }
-
-
- /*
- * Write out a bookmarks header entry. See comment at the top of
- * bm_measure_Header for the format used. Assume we start writing at
- * the start of the buffer passed in. Return a pointer to where the
- * buffer ends when we get done.
- */
- PRIVATE char*
- bm_write_Header(char* buffer, BM_Entry* item, XP_Bool bLongFormat, int nIndent)
- {
- long iLen;
- BM_Date lVal;
- BM_Type type;
- uint32 children;
- BM_Entry* child = NULL;
-
- if (!item || !buffer)
- return buffer;
-
- XP_ASSERT(BM_ISHEADER(item));
-
- if (bLongFormat)
- {
- /* copy the type */
- type = item->type;
- iLen = sizeof(BM_Type);
- XP_MEMCPY(buffer, &type, iLen);
- buffer += iLen;
-
- /* copy the name */
- if (item->name)
- {
- iLen = XP_STRLEN(item->name);
- XP_MEMCPY(buffer, item->name, iLen);
- buffer += iLen;
- }
- /* put the \n terminator on */
- *buffer++ = '\n';
-
- /* addition date */
- lVal = item->addition_date;
- iLen = sizeof(BM_Date);
- XP_MEMCPY(buffer, &lVal, iLen);
- buffer += iLen;
-
- /* number of children */
- children = item->d.header.childCount;
- iLen = sizeof(uint32);
- XP_MEMCPY(buffer, &children, iLen);
- buffer += iLen;
-
- /* copy the description */
- if (item->description)
- {
- iLen = XP_STRLEN(item->description);
- XP_MEMCPY(buffer, item->description, iLen);
- buffer += iLen;
- }
- /* put the \n terminator on */
- *buffer++ = '\0';
-
- }
- else
- {
- XP_MEMSET(buffer, ' ', nIndent);
- buffer += nIndent;
- if(item->name)
- {
- XP_STRCPY(buffer, item->name);
- buffer += XP_STRLEN(item->name);
- }
- *buffer++ = '\n';
- }
-
- child = item->d.header.children;
- while (child)
- {
- switch (child->type)
- {
- case BM_TYPE_URL:
- case BM_TYPE_ALIAS:
- buffer = bm_write_URL(buffer, child, bLongFormat, nIndent + TEXT_INDENT);
- break;
- case BM_TYPE_HEADER:
- buffer = bm_write_Header(buffer, child, bLongFormat, nIndent + TEXT_INDENT);
- break;
- case BM_TYPE_SEPARATOR:
- buffer = bm_write_Separator(buffer, child, bLongFormat, nIndent + TEXT_INDENT);
- break;
- default:
- break;
- }
- child = child->next;
- }
-
- return buffer;
- }
-
- /*
- * Take a separator packed in a block the way bm_write_Separator packs it.
- * Return the new item if we created one
- */
- PRIVATE BM_Entry*
- bm_read_Separator(char* buffer, XP_Bool bLongFormat, int32* lBytesEaten)
- {
- BM_Entry* new_item = NULL;
-
- if (!buffer)
- return NULL;
-
- if (bLongFormat)
- {
- /* for now the separator written has only the type.
- since that was already read in before this was clled
- we have nothing to eat here */
- new_item = bm_NewSeparator();
- *lBytesEaten = 0;
- }
- else
- {
- /* we should really strip leading whitespace */
- new_item = bm_NewSeparator();
- *lBytesEaten = XP_STRLEN(buffer) + 1;
- }
-
- return new_item;
- }
-
- /*
- * Take a URL packed in a block the way bm_write_URL packs it.
- * Return the new item if we created one
- */
- PRIVATE BM_Entry*
- bm_read_url_long(char* buffer, XP_Bool bLongFormat, int32* lBytesEaten)
- {
- BM_Entry* new_item = NULL;
-
- if (!buffer)
- return NULL;
-
- if (bLongFormat)
- {
- BM_Date addition;
- BM_Date visit;
- BM_Date modified;
-
- /* get the name */
- char* name = buffer;
- char* address = strchr(name, '\n');
- char* description = NULL;
- char* ptr;
- if (!address)
- return NULL;
- *address++ = '\0';
-
- /* get the address */
- ptr = strchr(address, '\n');
- if(!ptr)
- return NULL;
- *ptr++ = '\0';
-
- /* addition date */
- XP_MEMCPY(&addition, ptr, sizeof(BM_Date));
- ptr += sizeof(BM_Date);
-
- /* visiting date */
- XP_MEMCPY(&visit, ptr, sizeof(BM_Date));
- ptr += sizeof(BM_Date);
-
- /* modified date */
- XP_MEMCPY(&modified, ptr, sizeof(BM_Date));
- ptr += sizeof(BM_Date);
-
- /* get the description (it should be NULL terminated) */
- description = ptr;
-
- /* we should really strip leading whitespace */
- new_item = BM_NewUrl(name, address, 0, visit);
- new_item->addition_date = addition;
- new_item->description = XP_STRDUP(description);
- new_item->d.url.last_modified = modified;
- *lBytesEaten = XP_STRLEN(description) + (description - buffer) + 1;
-
- }
- else
- {
- char* end = strchr(buffer, '\n');
-
- /* if there was a return NULL terminate the current string */
- if (end)
- *end++ = '\0';
-
- /* we should really strip leading whitespace */
- new_item = BM_NewUrl(buffer, buffer, 0, 0);
- new_item->addition_date = XP_TIME();
- *lBytesEaten = XP_STRLEN(buffer) + 1;
- }
-
- return new_item;
- }
-
- /*
- * Take a header and children packed in a block the way bm_write_Header
- * packs it. Return the new header item if we created one
- */
- PRIVATE BM_Entry*
- bm_read_header_long(MWContext* context, char* buffer, XP_Bool bLongFormat,
- int32* lBytesEaten)
- {
- uint32 kids = 0;
- BM_Type type;
- BM_Entry* new_item = NULL;
- BM_Entry* kid = NULL;
- char* name = NULL;
- char* ptr = NULL;
- char* description = NULL;
- BM_Date addition;
- uint32 i;
- int32 lEat;
-
- if (!buffer)
- return NULL;
-
- /* can only read long format headers */
- if (bLongFormat)
- {
- /* get the name */
- name = buffer;
- ptr = strchr(name, '\n');
- description = NULL;
- if (!ptr)
- return NULL;
-
- /* skip over the \n but change it to a \0 so strcpy() will work */
- *ptr++ = '\0';
-
- /* addition date */
- XP_MEMCPY(&addition, ptr, sizeof(BM_Date));
- ptr += sizeof(BM_Date);
-
- /* number of children to read */
- XP_MEMCPY(&kids, ptr, sizeof(uint32));
- ptr += sizeof(uint32);
-
- /* get the description (it should be NULL terminated) */
- description = ptr;
-
- /* we should really strip leading whitespace */
- new_item = BM_NewHeader(name);
- new_item->addition_date = addition;
- new_item->description = XP_STRDUP(description);
- *lBytesEaten = XP_STRLEN(description) + (description - buffer) + 1;
-
- /* handle all of the kids now */
- if (kids)
- {
- buffer += *lBytesEaten;
-
- for (i = 0; i < kids; i++)
- {
- /* determine the type of the next entry */
- XP_MEMCPY(&type, buffer, sizeof(BM_Type));
- buffer += sizeof(BM_Type);
- *lBytesEaten += sizeof(BM_Type);
-
- switch (type)
- {
- case BM_TYPE_URL:
- kid = bm_read_url_long(buffer, bLongFormat, &lEat);
- *lBytesEaten += lEat;
- buffer += lEat;
- bm_AppendChildToHeader(context, new_item, kid);
- break;
- case BM_TYPE_ALIAS:
- break;
- case BM_TYPE_HEADER:
- kid = bm_read_header_long(context, buffer, bLongFormat, &lEat);
- *lBytesEaten += lEat;
- buffer += lEat;
- bm_AppendChildToHeader(context, new_item, kid);
- break;
- case BM_TYPE_SEPARATOR:
- kid = bm_read_Separator(buffer, bLongFormat, &lEat);
- *lBytesEaten += lEat;
- buffer += lEat;
- bm_AppendChildToHeader(context, new_item, kid);
- break;
- case 12345:
- /* Ah ha! this is the end marker we wrote. Something
- terribly wrong here. We shouldn't have hit this
- before we read all the kids in. */
- abort();
- break;
- default:
- /* bogus type. Who knows whats going on. Just quit and get out */
- break;
- }
-
- }
-
- }
- }
-
- return new_item;
- }
-
- PRIVATE int32
- bm_measure(BM_Entry* root, XP_Bool bLongFormat, int32 indent)
- {
- int32 iSpace = 0;
- BM_Entry* child;
-
- XP_ASSERT(root);
- XP_ASSERT(BM_ISHEADER(root));
-
- child = root->d.header.children;
-
- while (child)
- {
- switch (child->type)
- {
- case BM_TYPE_URL:
- if (BM_ISSELECTED(child))
- iSpace += bm_measure_URL(child, bLongFormat, indent);
- break;
- case BM_TYPE_ALIAS:
- iSpace += bm_measure_Alias(child, bLongFormat, indent + TEXT_INDENT);
- break;
- case BM_TYPE_HEADER:
- if (BM_ISSELECTED(child))
- iSpace += bm_measure_Header(child, bLongFormat, indent);
- else
- if (! BM_ISFOLDED(child))
- iSpace += bm_measure(child, bLongFormat, indent);
- break;
- case BM_TYPE_SEPARATOR:
- if (BM_ISSELECTED(child))
- iSpace += bm_measure_Separator(child, bLongFormat, indent);
- break;
- }
- child = child->next;
- }
- return iSpace;
- }
-
- PRIVATE char*
- bm_write(char* buffer, BM_Entry* root, XP_Bool bLongFormat, int32 indent)
- {
- BM_Entry* child;
-
- XP_ASSERT(root);
- XP_ASSERT(BM_ISHEADER(root));
-
- child = root->d.header.children;
-
- while (child)
- {
- switch (child->type)
- {
- case BM_TYPE_URL:
- case BM_TYPE_ALIAS:
- if (BM_ISSELECTED(child))
- buffer = bm_write_URL(buffer, child, bLongFormat, indent);
- break;
-
- case BM_TYPE_HEADER:
- if (BM_ISSELECTED(child))
- buffer = bm_write_Header(buffer, child, bLongFormat, indent);
- else
- if (! BM_ISFOLDED(child))
- buffer = bm_write(buffer, child, bLongFormat, indent);
- break;
- case BM_TYPE_SEPARATOR:
- if (BM_ISSELECTED(child))
- buffer = bm_write_Separator(buffer, child, bLongFormat, indent);
- break;
- }
- child = child->next;
- }
- return buffer;
- }
-
- /*
- * Allocate and return a string that contains the text representation of
- * a list of bookmarks entries from specified selections in a History window.
- * The caller is responsible for freeing the string
- */
- PUBLIC char *
- BM_ClipCopyHistorySelection( void *pHistCsr, uint32 *pSelections, int iCount, int *pSize, XP_Bool bLongFormat )
- {
- int i, iLen, iSize = 0;
- uint16 marker;
- char * pStorage = NULL;
- char * pStgCsr = NULL;
- BM_Entry * pBM = NULL;
- BM_Entry * pPrevBM = NULL;
- BM_Entry * pCsr = NULL;
- BM_Entry * pBMList = NULL;
-
- if( !pHistCsr || !pSelections || iCount <= 0 )
- {
- return NULL;
- }
-
- /*
- * Build the list of BM_Entrys and calc the total size
- */
- for( i = 0; i < iCount; i++ )
- {
- gh_HistEntry *pHistEntry = GH_GetRecord( pHistCsr, pSelections[i] );
- if( !pHistEntry )
- {
- /* In case history file was somehow compromised */
- continue;
- }
-
- /*
- * Map the gh_HistEntry to the BM_Entry
- */
-
- pBM = (BM_Entry *)XP_ALLOC( sizeof(BM_Entry) );
- XP_MEMSET( pBM, 0, sizeof(BM_Entry) );
- if( !pPrevBM )
- {
- pBMList = pBM;
- }
- else
- {
- pPrevBM->next = pBM;
- }
- pPrevBM = pBM;
-
- /* type */
- pBM->type = BM_TYPE_URL;
-
- if( bLongFormat )
- {
- /* name */
- iLen = pHistEntry->pszName ? XP_STRLEN( pHistEntry->pszName )+1 : 0;
- pBM->name = iLen ? (char *)XP_ALLOC( iLen*sizeof(char) ) : NULL;
- if( iLen )
- {
- XP_STRCPY( pBM->name, pHistEntry->pszName );
- }
-
- /* addition date */
- time( &pBM->addition_date );
-
- /* last visit date */
- pBM->d.url.last_visit = pHistEntry->last_accessed;
-
- /* last modified */
- time( &pBM->d.url.last_modified );
-
- /* description */
- pBM->description = NULL;
- }
-
- /* address */
- iLen = pHistEntry->address ? XP_STRLEN( pHistEntry->address )+1 : 0;
- pBM->d.url.address = iLen ? (char *)XP_ALLOC( iLen*sizeof(char) ) : NULL;
- if( iLen )
- {
- XP_STRCPY( pBM->d.url.address, pHistEntry->address );
- }
-
-
- /*
- * Calc the size
- */
-
- iSize += bm_measure_URL( pBM, bLongFormat, 0 );
- }
-
- if( bLongFormat )
- {
- iSize += sizeof(uint16);
- }
-
- /* Leave room for the termination character */
- iSize++;
-
- #ifdef XP_WIN16
- if( (uint16)iSize > (uint16)(32*1024-1) )
- {
- return NULL;
- }
- #endif
-
- /* Allocate the storage */
- pStorage = pStgCsr = (char *)XP_ALLOC( iSize*sizeof(char) );
- if( !pStorage )
- {
- return NULL;
- }
-
- /* Copy the bookmarks to the storage */
- pCsr = pBMList;
- while( pCsr )
- {
- pStgCsr = bm_write_URL( pStgCsr, pCsr, bLongFormat, 0 );
-
- pPrevBM = pCsr;
-
- pCsr = pCsr->next;
-
- /* Free the entry */
- pPrevBM->next = NULL;
- bm_ShallowFreeEntry( pPrevBM );
- }
-
- if (bLongFormat)
- {
- /* Write the end-of-list marker */
- marker = 12345;
- XP_MEMCPY( pStgCsr, &marker, 2 );
- pStgCsr += sizeof(uint16);
- }
-
- /* End the string */
- *pStgCsr++ = '\0';
- *pSize = (pStgCsr - pStorage);
-
- return pStorage;
- }
-
-
- /*
- * Allocate and return a string that contains the text representation of
- * a list of bookmarks entries (including headers and their contents).
- * The caller is responsible for freeing the string
- */
- PUBLIC char*
- BM_ConvertSelectionsToBlock(MWContext* context,
- XP_Bool bLongFormat,
- int32* lTotalLen)
- {
- uint16 marker;
- int32 iSpace = 0;
- char* pString;
- char* pOriginal;
-
- BM_Entry* tmp;
-
- CHKCONTEXT(context);
-
- tmp = BM_GetRoot(context);
- iSpace = bm_measure(tmp, bLongFormat, 0);
-
- /* leave room for end of list marker */
- if (bLongFormat)
- iSpace += sizeof(uint16);
-
- /* leave room for the termination character */
- iSpace++;
-
- #ifdef XP_WIN16
- if (iSpace > 32000)
- return NULL;
- #endif
-
- /* allocate the string */
- pOriginal = pString = (char*)XP_ALLOC(iSpace * sizeof(char));
- if (!pString)
- return NULL;
-
- /* Make a big string */
- pString = bm_write(pString, tmp, bLongFormat, 0);
-
- /* stick the end of list marker on so that when we are decoding this */
- /* block we know when we are done */
- if (bLongFormat)
- {
- marker = 12345;
- XP_MEMCPY(pString, &marker, 2);
- pString += sizeof(uint16);
- }
-
- /* end the string and return the total length to our caller */
- *pString++ = '\0';
- *lTotalLen = (pString - pOriginal);
- return pOriginal;
- }
-
-
- /*
- * Take a block of memory formatted by BM_ConvertSelectionsToBlock and insert
- * the items it represents into the bookmarks following 'item'. If item is
- * NULL insert at the beginning of the bookmarks.
- */
- PUBLIC void
- BM_InsertBlockAt(MWContext* context,
- char* pOriginalBlock,
- BM_Entry* addTo,
- XP_Bool bLongFormat,
- int32 lTotalLen)
- {
- BM_Type type;
- int32 lBytesEaten = 0; /* total number of bytes eaten */
- int32 lEat; /* number of bytes eaten on this item */
- char* pCurrentPos;
- char* pBlock;
- BM_Entry* tmp;
- BM_Entry* item;
- XP_Bool first = TRUE;
-
- CHKCONTEXTVOID(context);
- if (!pOriginalBlock) return;
-
- if (addTo == NULL) addTo = BM_GetRoot(context);
-
- /* make a copy of the string we can write into */
- pCurrentPos = pBlock = (char*) XP_ALLOC(lTotalLen + 1);
- if (!pBlock) return;
-
- bm_start_batch(context);
- /* copy the data over and make sure we are NULL terminated to make life
- easier */
- XP_MEMCPY(pBlock, pOriginalBlock, lTotalLen);
- pBlock[lTotalLen] = '\0';
-
- /* long format can have all kinds of different types of things in it */
- if (bLongFormat) {
- while (lBytesEaten < lTotalLen) {
- /* determine the type of the next entry */
- XP_MEMCPY(&type, pCurrentPos, sizeof(BM_Type));
- pCurrentPos += sizeof(BM_Type);
- lBytesEaten += sizeof(BM_Type);
-
- item = NULL;
-
- switch (type) {
- case BM_TYPE_URL:
- item = bm_read_url_long(pCurrentPos, bLongFormat, &lEat);
- lBytesEaten += lEat;
- pCurrentPos += lEat;
- break;
-
- case BM_TYPE_ALIAS:
- break;
-
- case BM_TYPE_HEADER:
- item = bm_read_header_long(context, pCurrentPos, bLongFormat, &lEat);
- lBytesEaten += lEat;
- pCurrentPos += lEat;
- break;
-
- case BM_TYPE_SEPARATOR:
- item = bm_read_Separator(pCurrentPos, bLongFormat, &lEat);
- lBytesEaten += lEat;
- pCurrentPos += lEat;
- break;
-
- case 12345:
- /* Ah ha! this is the end marker we wrote! remember... */
- XP_ASSERT((lBytesEaten+1) == lTotalLen);
- break;
- default:
- /* bogus type. Who knows whats going on. Just quit and
- get out */
- goto GETOUT;
-
- break;
- }
- if (item) {
- if (first && BM_ISHEADER(addTo) && !BM_ISFOLDED(addTo)) {
- /* Adding inside a folder as first child. */
- BM_PrependChildToHeader(context, addTo, item);
- } else {
- bm_InsertItemAfter(context, addTo, item, FALSE);
- }
- addTo = item;
- first = FALSE;
- }
- }
- } else {
- item = NULL;
- /* short format is just a list of URLs separated by \n's */
- while (lBytesEaten < lTotalLen) {
- item = bm_read_url_long(pCurrentPos, bLongFormat, &lEat);
- lBytesEaten += lEat;
- pCurrentPos += lEat;
-
- if (item) {
- tmp = addTo->next;
- addTo->next = item;
- item->next = tmp;
- addTo = item;
- }
- /* if we just walked over a \0 we are done */
- if (pOriginalBlock[lBytesEaten - 1] == '\0') {
- lBytesEaten = lTotalLen;
- }
- }
- }
-
- GETOUT:
- /* mark the bookmark list as changed and clean up */
- bm_SetModified(context, TRUE);
- XP_FREE(pBlock);
- bm_end_batch(context);
- }
-
-
-
-
- static void
- bm_make_alias(MWContext* context, BM_Entry* entry, void* closure)
- {
- BM_Entry* newAlias;
- int32 index;
-
- CHKCONTEXTVOID(context);
-
- if (BM_ISURL(entry)) {
- newAlias = bm_NewAlias(entry);
- if (!newAlias) return;
-
- bm_InsertItemAfter(context, entry, newAlias, FALSE);
-
- index = BM_GetIndex(context, newAlias);
- if (index > 0) {
- bm_refresh(context, index, BM_LAST_CELL);
- }
- }
- }
-
- PUBLIC void
- BM_MakeAliases(MWContext* context)
- {
- CHKCONTEXTVOID(context);
- bm_start_batch(context);
- BM_EachSelectedEntryDo(context, bm_make_alias, NULL);
- bm_SyncCount(context);
- bm_end_batch(context);
- }
-
-
- BM_Entry*
- BM_GetAliasOriginal(BM_Entry* entry)
- {
- XP_ASSERT(BM_ISALIAS(entry));
- return BM_ISALIAS(entry) ? entry->d.alias.original : NULL;
- }
-
-
- static XP_Bool
- bm_SelectionIsContiguous_1(MWContext* context, BM_Entry* entry,
- XP_Bool* started, XP_Bool* finished)
- {
- XP_Bool result;
- for (; entry ; entry = entry->next) {
- if (BM_ISSELECTED(entry)) {
- if (*finished) return FALSE;
- *started = TRUE;
- } else {
- if (*started) *finished = TRUE;
- }
- if (BM_ISHEADER(entry) && !BM_ISFOLDED(entry)) {
- result = bm_SelectionIsContiguous_1(context, entry->d.header.children,
- started, finished);
- if (!result) return result;
- }
- }
- return TRUE;
- }
-
- static XP_Bool
- bm_SelectionIsContiguous(MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- XP_Bool started = FALSE;
- XP_Bool finished = FALSE;
- if (f->gSelectionCount < 0) bm_SyncSelection(context);
- if (f->gSelectionCount < 2) return TRUE;
- return bm_SelectionIsContiguous_1(context, BM_GetRoot(context),
- &started, &finished);
- }
-
- XP_Bool BM_FindCommandStatus(MWContext* context, BM_CommandType command)
- {
- BM_Frame* f = GETFRAME(context);
- int32 length;
-
- CHKCONTEXT(context);
-
- if (f->gSelectionCount < 0) bm_SyncSelection(context);
-
- switch (command) {
- case BM_Cmd_Invalid:
- return FALSE;
-
- case BM_Cmd_Open: /**/
- case BM_Cmd_ImportBookmarks:
- case BM_Cmd_SaveAs: /**/
- return TRUE;
-
- case BM_Cmd_Close: /**/
- return TRUE;
-
- case BM_Cmd_Undo:
- return UNDO_CanUndo(f->undo);
- case BM_Cmd_Redo:
- return UNDO_CanRedo(f->undo);
-
- case BM_Cmd_Cut:
- case BM_Cmd_Copy:
- case BM_Cmd_Delete:
- return (f->gSelectionCount > 0);
-
- case BM_Cmd_Paste:
- return BMFE_GetClipContents(context, &length) ? TRUE : FALSE;
- break;
-
-
- case BM_Cmd_SelectAllBookmarks: /**/
- return TRUE;
-
- case BM_Cmd_Find:
- return TRUE;
-
- case BM_Cmd_FindAgain:
- return ((f->gFindInfo != NULL) && (f->gFindInfo->textToFind != NULL));
-
- case BM_Cmd_BookmarkProps: /**/
- return (f->gSelectionCount == 1 &&
- !(f->gSelectionMask & BM_TYPE_SEPARATOR));
-
- case BM_Cmd_Sort_Name:
- case BM_Cmd_Sort_Name_Asc:
- case BM_Cmd_Sort_Address:
- case BM_Cmd_Sort_Address_Asc:
- case BM_Cmd_Sort_AddDate:
- case BM_Cmd_Sort_AddDate_Asc:
- case BM_Cmd_Sort_LastVisit:
- case BM_Cmd_Sort_LastVisit_Asc:
- case BM_Cmd_Sort_Natural:
- if (f->gSelectionCount == 0) return FALSE;
- if (f->gSelectionCount == 1) {
- return f->gSelectionMask == BM_TYPE_HEADER;
- }
- return bm_SelectionIsContiguous(context);
-
- case BM_Cmd_InsertBookmark:
- case BM_Cmd_InsertHeader:
- return TRUE;
-
- case BM_Cmd_InsertSeparator:
- return context->type == MWContextBookmarks;
-
- case BM_Cmd_GotoBookmark:
- if (context->type == MWContextBookmarks) {
- return (f->gSelectionCount == 1 &&
- (f->gSelectionMask & (BM_TYPE_URL | BM_TYPE_ALIAS)));
- } else {
- return f->gSelectionCount > 0;
- }
-
- case BM_Cmd_MakeAlias:
- return (f->gSelectionCount == 1 &&
- (f->gSelectionMask & BM_TYPE_URL));
-
- case BM_Cmd_SetAddHeader:
- return (context->type == MWContextBookmarks &&
- f->gSelectionCount == 1 &&
- (f->gSelectionMask & BM_TYPE_HEADER) &&
- BM_FirstSelectedItem(context) != f->addheader);
-
- case BM_Cmd_SetMenuHeader:
- return (context->type == MWContextBookmarks &&
- f->gSelectionCount == 1 &&
- (f->gSelectionMask & BM_TYPE_HEADER) &&
- BM_FirstSelectedItem(context) != f->menuheader);
-
- default:
- XP_ASSERT(0);
- break;
- }
- return FALSE;
- }
-
- static void
- bm_open_file(MWContext* context, char* newFile, void* closure)
- {
- if (newFile) {
- #ifdef XP_WIN
- BMFE_ChangingBookmarksFile();
- #endif
-
- BM_ReadBookmarksFromDisk(context, newFile, NULL);
-
- #ifdef XP_WIN
- BMFE_ChangedBookmarksFile();
- #endif
-
- XP_FREE(newFile);
- }
- }
-
-
- /* LI_STUFF give li the ability to open a new bookmarks file */
- void
- BM_Open_File(MWContext* context, char* newFile)
- {
- bm_open_file(context, newFile, NULL);
- }
-
-
- static void
- bm_import_file(MWContext* context, char* newFile, void* closure)
- {
- BM_Frame* f = GETFRAME(context);
- bm_start_batch(context);
- UNDO_DiscardAll(f->undo);
- if (newFile) {
- BM_Entry* oldroot = f->gBookmarks;
- BM_Entry* oldmenuheader = f->menuheader;
- BM_Entry* oldaddheader = f->addheader;
- BM_Entry* newroot;
- BM_Entry* entry;
- BM_Entry* next;
- char* oldfile = NULL;
- XP_StatStruct savedStat;
-
- if (f->gFile) {
- oldfile = XP_STRDUP(f->gFile);
- if (!oldfile) return; /* Out of memory... */
- }
- f->gBookmarks = NULL;
- f->gBookmarksModified = FALSE; /* Don't save now. */
-
- /* save real stat 'cause it's about to get busted */
- XP_MEMCPY(&savedStat, &(f->laststat), sizeof(savedStat));
-
- BM_ReadBookmarksFromDisk(context, newFile, NULL);
-
- /* restore real stat */
- XP_MEMCPY(&(f->laststat), &savedStat, sizeof(savedStat));
-
- newroot = f->gBookmarks;
- if (newroot && oldroot) {
- /* Make the new stuff be the first folder of the old stuff. */
- f->gBookmarks = oldroot;
- if (context->type == MWContextAddressBook) {
- XP_ASSERT(BM_ISHEADER(newroot));
- if (BM_ISHEADER(newroot)) {
- for (entry = newroot->d.header.children;
- entry;
- entry = next) {
- next = entry->next;
- entry->next = NULL;
- bm_AddChildToHeaderSorted(context, oldroot, entry);
- }
- }
- } else {
- BM_PrependChildToHeader(context, oldroot, newroot);
- }
- f->menuheader = oldmenuheader;
- f->addheader = oldaddheader;
- } else {
- f->gBookmarks = oldroot ? oldroot : newroot;
- }
- FREEIF(f->gFile);
- f->gFile = oldfile;
- oldfile = NULL;
- bm_SetModified(context, TRUE);
- bm_refresh(context, 1, BM_LAST_CELL);
- XP_FREE(newFile);
- }
- bm_end_batch(context);
- }
-
-
- static void
- bm_save_as_file(MWContext* context, char* saveName, void* closure)
- {
- if (saveName) {
- BM_SaveBookmarks(context, saveName);
- XP_FREE(saveName);
- }
- }
-
-
- static int
- bm_comparenames(const void* e1, const void* e2)
- {
- #ifdef INTL_SORT
- return XP_StrColl((*((BM_Entry**)e1))->name, (*((BM_Entry**)e2))->name);
- #else
- return XP_STRCMP((*((BM_Entry**)e1))->name, (*((BM_Entry**)e2))->name);
- #endif
- }
- static int
- bm_comparenames_Asc(const void* e1, const void* e2)
- {
- #ifdef INTL_SORT
- return XP_StrColl((*((BM_Entry**)e2))->name, (*((BM_Entry**)e1))->name);
- #else
- return XP_STRCMP((*((BM_Entry**)e2))->name, (*((BM_Entry**)e1))->name);
- #endif
- }
-
- static int bm_compare_address( const void *elem1, const void *elem2 )
- {
- BM_Entry *p1 = *(BM_Entry **)elem1;
- BM_Entry *p2 = *(BM_Entry **)elem2;
-
- if( !(p1->type == BM_TYPE_URL ||
- p1->type == BM_TYPE_ADDRESS) )
- {
- if( !(p2->type == BM_TYPE_URL ||
- p2->type == BM_TYPE_ADDRESS) )
- {
- return 0;
- }
- return -1;
- }
- else if( !(p2->type == BM_TYPE_URL ||
- p2->type == BM_TYPE_ADDRESS) )
- {
- return 1;
- }
-
- /* Note we rely on d.url.address is at same mem address as d.address.address */
-
- #ifdef INTL_SORT
- return XP_StrColl( p1->d.url.address, p2->d.url.address );
- #else
- return XP_STRCMP( p1->d.url.address, p2->d.url.address );
- #endif
- }
- static int bm_compare_address_Asc( const void *elem1, const void *elem2 )
- {
- BM_Entry *p2 = *(BM_Entry **)elem1;
- BM_Entry *p1 = *(BM_Entry **)elem2;
-
- if( !(p1->type == BM_TYPE_URL ||
- p1->type == BM_TYPE_ADDRESS) )
- {
- if( !(p2->type == BM_TYPE_URL ||
- p2->type == BM_TYPE_ADDRESS) )
- {
- return 0;
- }
- return -1;
- }
- else if( !(p2->type == BM_TYPE_URL ||
- p2->type == BM_TYPE_ADDRESS) )
- {
- return 1;
- }
-
- /* Note we rely on d.url.address is at same mem address as d.address.address */
-
- #ifdef INTL_SORT
- return XP_StrColl( p1->d.url.address, p2->d.url.address );
- #else
- return XP_STRCMP( p1->d.url.address, p2->d.url.address );
- #endif
- }
-
- #ifdef SUNOS4
- /* difftime() doesn't seem to exist on SunOS anywhere. -mcafee */
- static double difftime(time_t time1, time_t time0)
- {
- return (double) (time1 - time0);
- }
- #endif
-
- static int bm_compare_time (time_t time1, time_t time0)
- {
- double diff = difftime( time1, time0 );
-
- if (diff > 0.0) return 1;
- if (diff < 0.0) return -1;
-
- return 0;
- }
-
- static int bm_compare_addition_date( const void *elem1, const void *elem2 )
- {
- BM_Entry *p1 = *(BM_Entry **)elem1;
- BM_Entry *p2 = *(BM_Entry **)elem2;
-
- return bm_compare_time( p2->addition_date, p1->addition_date );
- }
- static int bm_compare_addition_date_Asc( const void *elem1, const void *elem2 )
- {
- BM_Entry *p2 = *(BM_Entry **)elem1;
- BM_Entry *p1 = *(BM_Entry **)elem2;
-
- return bm_compare_time( p2->addition_date, p1->addition_date );
- }
-
- static int bm_compare_natural( const void *elem1, const void *elem2 )
- {
- BM_Entry *p2 = *(BM_Entry **)elem1;
- BM_Entry *p1 = *(BM_Entry **)elem2;
-
- return (p2->iNaturalIndex >= p1->iNaturalIndex) ? 1 : -1;
- }
-
- static int bm_compare_last_visit( const void *elem1, const void *elem2 )
- {
- BM_Entry *p1 = *(BM_Entry **)elem1;
- BM_Entry *p2 = *(BM_Entry **)elem2;
- if( p2->type != BM_TYPE_URL )
- {
- if( p1->type != BM_TYPE_URL )
- {
- return 0;
- }
- return -1;
- }
- else if( p1->type != BM_TYPE_URL )
- {
- return 1;
- }
-
- return bm_compare_time( p2->d.url.last_visit, p1->d.url.last_visit );
- }
- static int bm_compare_last_visit_Asc( const void *elem1, const void *elem2 )
- {
- BM_Entry *p2 = *(BM_Entry **)elem1;
- BM_Entry *p1 = *(BM_Entry **)elem2;
- if( p2->type != BM_TYPE_URL )
- {
- if( p1->type != BM_TYPE_URL )
- {
- return 0;
- }
- return -1;
- }
- else if( p1->type != BM_TYPE_URL )
- {
- return 1;
- }
-
- return bm_compare_time( p2->d.url.last_visit, p1->d.url.last_visit );
- }
-
- static void
- bm_SortSelected_1(MWContext* context, BM_Entry* header, BM_SortType enSortType )
- {
- BM_Frame* f = GETFRAME(context);
- BM_Entry** list = NULL;
- int numlist;
- BM_Entry* entry;
- BM_Entry* previous = NULL;
- int i;
- #ifdef XP_WIN
- int (__cdecl *pfSort)(const void *, const void *);
- #else
- int (*pfSort)(const void *, const void *);
- #endif
-
- XP_ASSERT(BM_ISHEADER(header));
-
- switch( enSortType )
- {
- case BM_Sort_Name:
- pfSort = bm_comparenames;
- break;
- case BM_Sort_Name_Asc:
- pfSort = bm_comparenames_Asc;
- break;
-
- case BM_Sort_Address:
- pfSort = bm_compare_address;
- break;
- case BM_Sort_Address_Asc:
- pfSort = bm_compare_address_Asc;
- break;
-
- case BM_Sort_AddDate:
- pfSort = bm_compare_addition_date;
- break;
- case BM_Sort_AddDate_Asc:
- pfSort = bm_compare_addition_date_Asc;
- break;
-
- case BM_Sort_LastVisit:
- pfSort = bm_compare_last_visit;
- break;
- case BM_Sort_LastVisit_Asc:
- pfSort = bm_compare_last_visit_Asc;
- break;
-
- case BM_Sort_Natural:
- default:
- pfSort = bm_compare_natural;
- break;
- }
-
- if (header->d.header.childCount == 0) return;
- if (BM_ISSELECTED(header) && f->gSelectionCount == 1) {
- numlist = header->d.header.childCount;
- list = (BM_Entry**) XP_ALLOC(numlist * sizeof(BM_Entry*));
- if (!list) return;
- for (i = 0, entry = header->d.header.children;
- i < numlist;
- i++, entry = entry->next) {
- list[i] = entry;
- }
- } else {
- i = 0;
- for (entry = header->d.header.children ; entry ; entry = entry->next) {
- if (BM_ISSELECTED(entry)) {
- if (list == NULL) {
- list = (BM_Entry**) XP_ALLOC(header->d.header.childCount *
- sizeof(BM_Entry*));
- if (list == NULL) return;
- }
- list[i++] = entry;
- } else {
- if (list == NULL) previous = entry;
- }
- }
- numlist = i;
- }
- if (list) {
- if (numlist > 1) {
- for (i=0 ; i<numlist ; i++) {
- if (list[i]->name == NULL) {
- list[i]->name = XP_STRDUP("");
- if (list[i]->name == NULL) return;
- }
- BM_RemoveChildFromHeader(context, header, list[i]);
- }
- XP_QSORT(list, numlist, sizeof(BM_Entry*), pfSort);
- for (i=0 ; i<numlist ; i++) {
- if (previous) {
- bm_InsertItemAfter(context, previous, list[i], FALSE);
- } else {
- BM_PrependChildToHeader(context, header, list[i]);
- }
- previous = list[i];
- }
- }
- XP_FREE(list);
- list = NULL;
- }
- for (entry = header->d.header.children ; entry ; entry = entry->next) {
- if (BM_ISHEADER(entry)) bm_SortSelected_1(context, entry, enSortType );
- }
- }
-
- static void
- bm_SortSilent_1(MWContext* context, BM_Entry* header, BM_SortType enSortType )
- {
- BM_Frame* f = GETFRAME(context);
- BM_Entry** list = NULL;
- int numlist;
- BM_Entry* entry;
- BM_Entry* previous = NULL;
- int i;
- XP_Bool bSelected = FALSE;
- #ifdef XP_WIN
- int (__cdecl *pfSort)(const void *, const void *);
- #else
- int (*pfSort)(const void *, const void *);
- #endif
-
- XP_ASSERT(BM_ISHEADER(header));
-
- switch( enSortType )
- {
- case BM_Sort_Name:
- pfSort = bm_comparenames;
- break;
- case BM_Sort_Name_Asc:
- pfSort = bm_comparenames_Asc;
- break;
-
- case BM_Sort_Address:
- pfSort = bm_compare_address;
- break;
- case BM_Sort_Address_Asc:
- pfSort = bm_compare_address_Asc;
- break;
-
- case BM_Sort_AddDate:
- pfSort = bm_compare_addition_date;
- break;
- case BM_Sort_AddDate_Asc:
- pfSort = bm_compare_addition_date_Asc;
- break;
-
- case BM_Sort_LastVisit:
- pfSort = bm_compare_last_visit;
- break;
- case BM_Sort_LastVisit_Asc:
- pfSort = bm_compare_last_visit_Asc;
- break;
-
- case BM_Sort_Natural:
- default:
- pfSort = bm_compare_natural;
- break;
- }
-
- if (header->d.header.childCount == 0) return;
- numlist = header->d.header.childCount;
- list = (BM_Entry**) XP_ALLOC(numlist * sizeof(BM_Entry*));
- if (!list) return;
- for (i = 0, entry = header->d.header.children;
- i < numlist;
- i++, entry = entry->next) {
- list[i] = entry;
- }
- if (numlist > 1) {
- for (i=0 ; i<numlist ; i++) {
- if (list[i]->name == NULL) {
- list[i]->name = XP_STRDUP("");
- if (list[i]->name == NULL) return;
- }
- if (BM_ISSELECTED(list[i])) {
- BM_CLEARFLAG(list[i], BM_ATTR_SELECTED);
- bSelected = TRUE;
- }
- BM_RemoveChildFromHeader(context, header, list[i]);
- if (bSelected) {
- BM_SETFLAG(list[i], BM_ATTR_SELECTED);
- bSelected = FALSE;
- }
- }
- XP_QSORT(list, numlist, sizeof(BM_Entry*), pfSort);
- for (i=0 ; i<numlist ; i++) {
- if (previous) {
- bm_InsertItemAfter(context, previous, list[i], FALSE);
- } else {
- BM_PrependChildToHeader(context, header, list[i]);
- }
- previous = list[i];
- }
- }
- XP_FREE(list);
- list = NULL;
- for (entry = header->d.header.children ; entry ; entry = entry->next) {
- if (BM_ISHEADER(entry)) bm_SortSilent_1(context, entry, enSortType );
- }
- }
-
- /*
- // Normalize bookmarks based on the current sort. Note the current sort
- // should be the natural sort order (aka BM_Sort_Natural) as no other
- // sort order has a mapping to the natural index.
- */
- static void
- bm_Normalize(MWContext* context, BM_Entry* at)
- {
- BM_Entry* nextChild;
- BM_Entry* children;
-
- int32 iNaturalIndex = 0;
-
- while (at) {
- nextChild = at->next;
- if (BM_ISHEADER(at)) {
- children = at->d.header.children;
- } else {
- children = NULL;
- }
-
- at->iNaturalIndex = iNaturalIndex++;
-
- if (children) {
- bm_Normalize(context, children);
- }
-
- at = nextChild;
- }
- }
-
- static void
- bm_SortSelected(MWContext* context, BM_SortType enSortType )
- {
- BM_Frame* f = GETFRAME(context);
- if (f->gSelectionCount < 0) bm_SyncSelection(context);
- if (f->enSortType == BM_Sort_Natural) bm_Normalize(context, BM_GetRoot(context));
- f->enSortType = enSortType;
- f->bSorting = TRUE;
- bm_SortSelected_1(context, BM_GetRoot(context), enSortType);
- f->bSorting = FALSE;
- bm_refresh(context, 1, BM_LAST_CELL);
- }
-
- static void
- bm_SortSilent(MWContext* context, BM_SortType enSortType )
- {
- BM_Frame* f = GETFRAME(context);
- if (f->gSelectionCount < 0) bm_SyncSelection(context);
- if (f->enSortType == BM_Sort_Natural) bm_Normalize(context, BM_GetRoot(context));
- f->enSortType = enSortType;
- f->bSorting = TRUE;
- bm_SortSilent_1(context, BM_GetRoot(context), enSortType);
- f->bSorting = FALSE;
- }
-
- static void bm_append_address_string(MWContext* context, BM_Entry* entry,
- void* closure);
-
- static void
- bm_append_fulladdress_string(MWContext* context, BM_Entry* entry,
- void* closure)
- {
- if (BM_ISALIAS(entry)) entry = entry->d.alias.original;
- if (entry->flags & BM_ATTR_MARKED) return;
- if (BM_ISHEADER(entry)) {
- BM_SETFLAG(entry, BM_ATTR_MARKED);
- for (entry = entry->d.header.children ; entry ; entry = entry->next) {
- bm_append_fulladdress_string(context, entry, closure);
- }
- } else if (BM_ISADDRESS(entry)) {
- bm_append_address_string(context, entry, closure);
- XP_ASSERT(entry->flags & BM_ATTR_MARKED);
- }
- }
-
- static void
- bm_append_address_string(MWContext* context, BM_Entry* entry, void* closure)
- {
- if (BM_ISALIAS(entry)) entry = entry->d.alias.original;
- if (entry->flags & BM_ATTR_MARKED) return;
- if (BM_ISADDRESS(entry) || BM_ISHEADER(entry)) {
- char* address =
- BM_ISHEADER(entry) ? BM_GetNickName(entry) : BM_GetAddress(entry);
- if (BM_ISHEADER(entry) && (address == NULL || *address == '\0')) {
- /* No nickname for a header, so we don't have anything to write down
- that we can remember later. Just write down all the members of
- this list. */
- bm_append_fulladdress_string(context, entry, closure);
- } else {
- #ifdef MOZ_MAIL_NEWS
- char** buf = (char**) closure;
- char* full = MSG_MakeFullAddress(BM_GetName(entry), address);
- if (full) {
- if (*buf) NET_SACat(buf, ", ");
- NET_SACat(buf, full);
- XP_FREE(full);
- }
- #endif /* MOZ_MAIL_NEWS */
- }
- }
- BM_SETFLAG(entry, BM_ATTR_MARKED);
- }
-
- char*
- BM_GetFullAddress(MWContext* context, BM_Entry* entry)
- {
- char* result = NULL;
- bm_append_address_string(context, entry, &result);
- return result;
- }
-
- static void
- bm_ComposeMessageToSelected(MWContext* context)
- {
- char* buf = NULL;
- char* tmp;
- URL_Struct *url_struct;
- bm_ClearMarkEverywhere(context);
- BM_EachSelectedEntryDo(context, bm_append_address_string, &buf);
- if (!buf) return;
- tmp = NET_Escape(buf, URL_PATH);
- XP_FREE(buf);
- buf = tmp;
- if (!buf) return;
- tmp = XP_Cat("mailto:?to=", buf, (char*)/*Win16*/ NULL);
- XP_FREE(buf);
- buf = tmp;
- if (!buf) return;
- url_struct = NET_CreateURLStruct (buf, NET_NORMAL_RELOAD);
- if (url_struct) {
- url_struct->internal_url = TRUE;
- FE_GetURL(context, url_struct);
- }
- XP_FREE(buf);
- }
-
-
- char*
- BM_ExpandHeaderString(MWContext* context, const char* value,
- XP_Bool expandfull)
- {
- BM_Frame* f = GETFRAME(context);
- char* name;
- char* address;
- char* curname;
- char* curaddress;
- char* pHashStr;
- int num;
- int i,j;
- XP_Bool found = FALSE;
- BM_Entry* entry;
- char* result = NULL;
- char* pTempStr = NULL;
- int tempBufLen = 0;
- CHKCONTEXT(context);
- #ifdef MOZ_MAIL_NEWS
- num = MSG_ParseRFC822Addresses(value, &name, &address);
- #else
- num = 0;
- #endif /* MOZ_MAIL_NEWS */
- curname = name;
- curaddress = address;
- bm_ClearMarkEverywhere(context);
- for (i=0 ; i<num ; i++) {
- pHashStr = NULL;
- if (XP_STRCHR(curaddress, '@') == NULL) {
- /* to make nicknames case-insensitive, we have to
- ** change the string here to be all lowercase before
- ** passing it to the hash lookup function */
-
- /* first make sure the temporary buffer we have
- ** is long enough for this string. If not, make
- ** a new one that is long enough. */
- int curlen;
- curlen = XP_STRLEN(curaddress);
- if (!pTempStr || (curlen > tempBufLen)) {
- FREEIF(pTempStr);
- pTempStr = XP_STRDUP(curaddress);
- tempBufLen = curlen;
- } else {
- /* just copy the string into the existing buffer */
- XP_STRCPY(pTempStr, curaddress);
- }
- if (pTempStr) {
- /* now the buffer is loaded with the string, change the string to lowercase */
- for (j = 0; j < curlen; j++) {
- if (isupper(pTempStr[j])) {
- pTempStr[j] = (char)tolower(pTempStr[j]);
- }
- }
- pHashStr = pTempStr; /* use the temp str for the hash function */
- } else {
- pHashStr = curaddress; /* use the old string if low on memory */
- }
- }
- if (pHashStr && (entry = XP_Gethash(f->nicknameTable, pHashStr, NULL)) != NULL) {
- found = TRUE;
- if (expandfull) {
- bm_append_fulladdress_string(context, entry, &result);
- } else {
- bm_append_address_string(context, entry, &result);
- }
- } else {
- if (result) NET_SACat(&result, ", ");
- if (*curname) {
- NET_SACat(&result, curname);
- NET_SACat(&result, " <");
- }
- NET_SACat(&result, curaddress);
- if (*curname) {
- NET_SACat(&result, ">");
- }
- }
- curname += XP_STRLEN(curname) + 1;
- curaddress += XP_STRLEN(curaddress) + 1;
- }
- FREEIF(name);
- FREEIF(address);
- FREEIF(pTempStr);
- if (!found) {
- FREEIF(result); /* Note this sets also result to NULL. */
- }
- return result;
- }
-
-
-
-
-
-
- void BM_ObeyCommand(MWContext* context, BM_CommandType command)
- {
- BM_Frame* f = GETFRAME(context);
- BM_Entry* firstSelected;
-
- CHKCONTEXTVOID(context);
-
- if (!BM_FindCommandStatus(context, command)) return;
-
- firstSelected = BM_FirstSelectedItem(context);
-
- bm_start_batch(context);
-
- switch (command) {
- case BM_Cmd_Invalid:
- break;
-
- case BM_Cmd_Open:
- FE_PromptForFileName(context, XP_GetString(XP_BKMKS_OPEN_BKMKS_FILE),
- 0, TRUE, FALSE, bm_open_file, NULL);
- break;
-
- case BM_Cmd_ImportBookmarks:
- FE_PromptForFileName(context,
- XP_GetString(context->type == MWContextAddressBook ?
- XP_BKMKS_IMPORT_ADDRBOOK : XP_BKMKS_IMPORT_BKMKS_FILE),
- 0, TRUE, FALSE, bm_import_file, NULL);
- break;
-
- case BM_Cmd_SaveAs:
- FE_PromptForFileName(context,
- XP_GetString(context->type == MWContextAddressBook ?
- XP_BKMKS_SAVE_ADDRBOOK : XP_BKMKS_SAVE_BKMKS_FILE),
- 0, FALSE, FALSE, bm_save_as_file, NULL);
- break;
-
- case BM_Cmd_Close:
- BM_SaveBookmarks(context, f->gFile);
- /* ### Maybe need to do more? */
- break;
-
- case BM_Cmd_Undo:
- UNDO_EndBatch(f->undo, NULL, NULL);
- UNDO_DoUndo(f->undo);
- UNDO_StartBatch(f->undo);
- bm_refresh(context, 1, BM_LAST_CELL);
- bm_SyncCount(context);
- break;
-
- case BM_Cmd_Redo:
- UNDO_EndBatch(f->undo, NULL, NULL);
- UNDO_DoRedo(f->undo);
- UNDO_StartBatch(f->undo);
- bm_refresh(context, 1, BM_LAST_CELL);
- bm_SyncCount(context);
- break;
-
- case BM_Cmd_Cut:
- bm_cut(context);
- break;
-
- case BM_Cmd_Copy:
- bm_copy(context);
- break;
-
- case BM_Cmd_Paste:
- bm_paste(context);
- break;
-
- case BM_Cmd_Delete:
- bm_delete(context);
- break;
-
- case BM_Cmd_SelectAllBookmarks:
- BM_SelectAll(context, TRUE);
- break;
-
- case BM_Cmd_Find:
- bm_CloseLastFind(context);
- bm_BeginFindBookmark(context);
- break;
-
- case BM_Cmd_FindAgain:
- bm_CloseLastFind(context);
- BM_DoFindBookmark(context, f->gFindInfo);
- break;
-
- case BM_Cmd_BookmarkProps:
- if (firstSelected) {
- BMFE_OpenBookmarksWindow(context);
- BMFE_EditItem(context, firstSelected);
- }
- break;
-
- case BM_Cmd_GotoBookmark:
- if (context->type == MWContextAddressBook) {
- bm_ComposeMessageToSelected(context);
- } else if (firstSelected) {
- BM_GotoBookmark(context, firstSelected);
- }
- break;
-
- case BM_Cmd_Sort_Name:
- case BM_Cmd_Sort_Name_Asc:
- case BM_Cmd_Sort_Address:
- case BM_Cmd_Sort_Address_Asc:
- case BM_Cmd_Sort_AddDate:
- case BM_Cmd_Sort_AddDate_Asc:
- case BM_Cmd_Sort_LastVisit:
- case BM_Cmd_Sort_LastVisit_Asc:
- case BM_Cmd_Sort_Natural:
- bm_SortSelected( context, command-BM_Cmd_Sort_Name );
- break;
-
- case BM_Cmd_InsertBookmark:
- bm_BeginEditNewUrl(context);
- break;
-
- case BM_Cmd_InsertHeader:
- bm_BeginEditNewHeader(context);
- break;
-
- case BM_Cmd_InsertSeparator:
- if (firstSelected) {
- bm_InsertItemAfter(context, firstSelected, bm_NewSeparator(), TRUE);
- bm_refresh(context, BM_GetIndex(context, firstSelected) + 1,
- BM_LAST_CELL);
- }
- break;
-
- case BM_Cmd_MakeAlias:
- BM_MakeAliases(context);
- break;
-
- case BM_Cmd_SetAddHeader:
- if (firstSelected) {
- BM_SetAddHeader(context, firstSelected);
- }
- break;
-
- case BM_Cmd_SetMenuHeader:
- if (firstSelected) {
- BM_SetMenuHeader(context, firstSelected);
- }
- break;
-
- default:
- XP_ASSERT(0);
-
- }
- bm_end_batch(context);
- }
-
-
-
- /* Make sure that the given entry is a real entry, and not a pointer that has
- since become invalid. */
-
- static XP_Bool
- bm_validate_entry(MWContext* context, BM_Entry* entry, BM_Entry* search)
- {
- for (; entry ; entry = entry->next) {
- if (entry == search) return TRUE;
- if (BM_ISHEADER(entry)) {
- if (bm_validate_entry(context, entry->d.header.children, search)) {
- return TRUE;
- }
- }
- }
- return FALSE;
- }
-
-
- static void
- bm_urlcheck_finished(URL_Struct* url_struct, int status, MWContext* context)
- {
- BM_Frame* f = GETFRAME(context);
- time_t now;
- char timestr[40];
- if (f) {
- struct BM_WhatsChangedInfo* w = (struct BM_WhatsChangedInfo *)&(f->whatschanged);
- BM_Entry* entry = (BM_Entry*) url_struct->fe_data;
- if (bm_validate_entry(context, BM_GetRoot(context), entry)) {
- const char* url = BM_GetAddress(entry);
- int32 oldstate = BM_GetChangedState(entry);
- BM_CLEARFLAG(entry, BM_ATTR_CHECKING);
- if (status >= 0) {
- if (url && XP_STRCMP(url_struct->address, url) == 0) {
- w->numreached++;
- entry->d.url.last_modified = url_struct->last_modified;
- if (entry->d.url.last_modified > entry->d.url.last_visit) {
- w->numchanged++;
- }
- }
- } else {
- entry->d.url.last_modified = 0;
- }
- if (BM_GetChangedState(entry) != oldstate) {
- bm_entry_changed(context, entry);
- bm_SetModified(context, TRUE);
- }
-
- now = time ((time_t *) 0);
-
- if (w->numreached == 0) {
- XP_STRCPY(timestr, "???");
- } else {
- int32 estimate = (now - w->starttime) * (w->total - w->numreached) /
- w->numreached;
- if (estimate < 2 * 60) {
- PR_snprintf(timestr, sizeof(timestr), XP_GetString(XP_BKMKS_SECONDS),
- estimate);
- } else if (estimate < 2 * 60 * 60) {
- PR_snprintf(timestr, sizeof(timestr), XP_GetString(XP_BKMKS_MINUTES),
- estimate / 60);
- } else {
- PR_snprintf(timestr, sizeof(timestr), XP_GetString(XP_BKMKS_HOURS_MINUTES),
- estimate / 3600, (estimate / 60) % 60);
- }
- }
- BMFE_UpdateWhatsChanged(context, url, w->numreached, w->total,
- timestr);
- }
-
- /* Check to see if we're all done. First check to see if we're in the
- middle of a batch operation; if we are, then we must be still setting
- things up and we got called here because we had an invalid bookmark
- and netlib called the exit routine immediately. In that case, we
- don't want to say we're all done; we're probably still sending
- URLs to netlib.
-
- If we're not in the middle of a batch operation, then we're all done
- if there are no more outstanding connections on our context. */
- if (f->batch_depth == 0 &&
- !NET_AreThereActiveConnectionsForWindow(context)) {
- BMFE_FinishedWhatsChanged(context, w->total, w->numreached,
- w->numchanged);
- }
- }
- }
-
- #ifdef XP_WIN16
- /* code segment is full, switch to a new segment */
- #pragma code_seg("BKMKS2_TEXT","CODE")
- #endif
-
-
-
- static void
- bm_urlcheck_start(MWContext* context, BM_Entry* entry)
- {
- BM_Frame* f = GETFRAME(context);
- char* url;
- URL_Struct* url_struct;
-
- XP_ASSERT(entry);
-
- if (BM_ISALIAS(entry)) {
- entry = entry->d.alias.original;
- }
- if (!entry) return;
-
- if (entry->flags & BM_ATTR_CHECKING) return;
-
- url = BM_GetAddress(entry);
- if (!url) return;
- url_struct = NET_CreateURLStruct(url, NET_SUPER_RELOAD);
- if (!url_struct) return;
- BM_SETFLAG(entry, BM_ATTR_CHECKING);
- url_struct->method = URL_HEAD_METHOD;
- url_struct->fe_data = entry;
- f->whatschanged.total++;
- NET_GetURL(url_struct, FO_PRESENT, context, bm_urlcheck_finished);
- }
-
-
-
-
- static void
- bm_start_whats_changed_1(MWContext* context, BM_Entry* entry,
- XP_Bool do_only_selected)
- {
- for ( ; entry ; entry = entry->next) {
- if (BM_ISURL(entry) || BM_ISALIAS(entry)) {
- if (!do_only_selected || BM_ISSELECTED(entry)) {
- bm_urlcheck_start(context, entry);
- }
- } else if (BM_ISHEADER(entry)) {
- /* Recur through the children. If we are selected and folded, then
- make sure we do all of our descendents. */
- bm_start_whats_changed_1(context, entry->d.header.children,
- (BM_ISSELECTED(entry) && BM_ISFOLDED(entry)) ?
- FALSE : do_only_selected);
- }
- }
- }
-
-
- static void
- bm_clear_check_attr(MWContext* context, BM_Entry* entry, void* closure)
- {
- BM_CLEARFLAG(entry, BM_ATTR_CHECKING);
- }
-
-
- int
- BM_StartWhatsChanged(MWContext* context, XP_Bool do_only_selected)
- {
- BM_Frame* f = GETFRAME(context);
- struct BM_WhatsChangedInfo* w;
- XP_ASSERT(context && context->type == MWContextBookmarks && f);
- if (!context || context->type != MWContextBookmarks || !f) return -1;
- w = &(f->whatschanged);
- BM_CancelWhatsChanged(context);
- XP_MEMSET(w, 0, sizeof(*w));
- w->starttime = time ((time_t *) 0);
-
- BM_EachEntryDo(context, bm_clear_check_attr, NULL);
-
- bm_start_batch(context);
- bm_start_whats_changed_1(context, BM_GetRoot(context), do_only_selected);
-
- #if 0
- minutes = f->whatschanged.total * 35 / 60;
- /* Assumes a maximum timeout of 35 seconds per
- connection. Need to not hard-code
- this... #### */
- if (minutes < 60) {
- /* Fix i18n ### */
- PR_snprintf(w->totaltime, sizeof(w->totaltime), "%ld minutes", minutes);
- } else {
- /* Fix i18n ### */
- PR_snprintf(w->totaltime, sizeof(w->totaltime), "%ld hours",
- (minutes / 60) + 1);
- }
- #endif
-
- BMFE_UpdateWhatsChanged(context, NULL, w->numreached, w->total,
- "???"); /* Fix i18n ### */
- bm_refresh(context, 1, BM_LAST_CELL);
- bm_end_batch(context);
- if (!NET_AreThereActiveConnectionsForWindow(context)) {
- /* All done, already (probably because nothing was selected). */
- BMFE_FinishedWhatsChanged(context, w->total, w->numreached,
- w->numchanged);
- }
- return 0;
- }
-
-
- int
- BM_CancelWhatsChanged(MWContext* context)
- {
- XP_InterruptContext(context);
- return 0;
- }
-
- void BM_ResetUndo(MWContext * context)
- {
- BM_Frame * f = GETFRAME(context);
- UNDO_DiscardAll( f->undo );
- }
-
-