/* ** File: hthotlst.c ** ** Description: Parser for hierarchical hotlist (HTML) file. ** All source code modifications to support hierarchical ** hotlists are enclosed with "#ifdef FEATURE_KAZAN_HOTLIST". ** ** Author(s): Scott Piette scott@spyglass.com ** Bradford L. Terrell brad@kazan.com ** ** Copyright: (c) 1994, 1995 by Spyglass, Inc. ** All Rights Reserved ** ** History: (Most recent first) ** ** 11/01/95 blt Modified DlgHotTree_AddTreeItem() to conditionally ** make items visible based on a new "FOLDER_STATE" ** keyword. ** 09/15/95 blt Modified DumpTreeItem() and WriteItem() to ** handle empty folders in the TreeView. ** 09/15/95 blt Modified DlgHotTree_AddTreeItem() and added ** AddRootToTreeView() to fix bug in hotlist ** parsing. This fix inserts top-level items ** into the tree as children of the root node ** rather than siblings. ** 09/05/95 blt Modified DlgHotTree_AddTreeItem() to use ** I_IMAGECALLBACK for folders in Image List. ** Modified to add a root node to Tree View. ** 08/25/95 blt Modified to use Windows TreeView control for ** hierarchical hotlists. */ #include "all.h" #ifdef FEATURE_KAZAN_HOTLIST static HTREEITEM parentTreeItem[MAX_HOTLIST_NESTING + 1]; static int parentItemIndex = 0; #endif #ifdef MAC extern void DlgHOT_RefreshHotlist (void); #endif extern void HotList_updatedisplay(int flag); static BOOL bHotListLoading; typedef struct _hotlist_stack_table { struct hash_table *hotlist_stack[MAX_HOTLIST_NESTING + 1]; int hotlist_stack_index; int hotlist_menu_index; } hotlist_stack_table; struct _hotlist_stack_table gHotListTable; far struct hash_table gHotList; /* HTML Object ** ----------- */ #define TITLE_LEN 512 struct _HTStructured { CONST HTStructuredClass *isa; CONST SGML_dtd *dtd; BOOL bInAnchor; BOOL bHaveAnchor; BOOL bInHeader; BOOL bHaveHeader; #ifdef FEATURE_KAZAN_HOTLIST BOOL bVisible; #endif char href[MAX_URL_STRING + 1]; char title[TITLE_LEN + 1]; /* TODO check this for overflow */ int lenTitle; char base_url[MAX_URL_STRING + 1]; struct hash_table *hash_stack[MAX_HOTLIST_NESTING + 1]; int hash_table_index; }; /* Flush Buffer ** ------------ */ PRIVATE void HTHotList_flush(HTStructured * me) { } /* Character handling ** ------------------ ** */ PRIVATE void HTHotList_put_character(HTStructured * me, char c) { switch (c) { case '\n': case '\t': case '\r': c = ' '; break; default: break; } if (me->bInAnchor || me->bInHeader) { if (!(c == ' ' && me->lenTitle == 0)) { me->title[me->lenTitle++] = c; } } } /* String handling ** --------------- */ PRIVATE void HTHotList_put_string(HTStructured * me, CONST char *s) { } PRIVATE void HTHotList_write(HTStructured * me, CONST char *s, int l) { } /* Start Element ** ------------- ** */ PRIVATE void HTHotList_start_element(HTStructured * me, int element_number, CONST BOOL * present, CONST char **value) { switch (element_number) { case HTML_DL: { #ifndef FEATURE_KAZAN_HOTLIST struct hash_table *new_hash; #endif if (me->bHaveHeader) { if (me->title[0]) { if (me->hash_table_index < MAX_HOTLIST_NESTING) { #ifdef FEATURE_KAZAN_HOTLIST if (parentItemIndex == 0) { HWND hWndTreeView = DlgHotTree_GetHotlistTreeViewWindow(); parentTreeItem[parentItemIndex] = DlgHotTree_AddTreeItem(TreeView_GetRoot(hWndTreeView), me->title, NULL, (HTREEITEM) TVI_LAST, I_IMAGECALLBACK, hWndTreeView, me->bVisible); } else parentTreeItem[parentItemIndex] = DlgHotTree_AddTreeItem(parentTreeItem[parentItemIndex - 1], me->title, NULL, (HTREEITEM) TVI_LAST, I_IMAGECALLBACK, DlgHotTree_GetHotlistTreeViewWindow(), me->bVisible); parentItemIndex++; #else new_hash = Hash_Create(); Hash_Add(me->hash_stack[me->hash_table_index++], me->title, NULL, new_hash); me->hash_stack[me->hash_table_index] = new_hash; /* Now add the back link to the hash */ Hash_Add(me->hash_stack[me->hash_table_index], HOTLIST_SUBMENU_LINK_TEXT, NULL, me->hash_stack[me->hash_table_index-1]); #endif } } me->bHaveHeader = FALSE; } else if (me->bHaveAnchor) { if (me->title[0]) { #ifdef FEATURE_KAZAN_HOTLIST if (parentItemIndex == 0) DlgHotTree_AddTreeItem(NULL, me->title, me->href, (HTREEITEM) TVI_LAST, DlgHotTree_GetWebPageBitmapIndex(), DlgHotTree_GetHotlistTreeViewWindow(), me->bVisible); else DlgHotTree_AddTreeItem(parentTreeItem[parentItemIndex - 1], me->title, me->href, (HTREEITEM) TVI_LAST, DlgHotTree_GetWebPageBitmapIndex(), DlgHotTree_GetHotlistTreeViewWindow(), me->bVisible); #else Hash_Add(me->hash_stack[me->hash_table_index], me->href, me->title, NULL); #endif } me->bHaveAnchor = FALSE; } } break; case HTML_DT: { if (me->bHaveAnchor) { if (me->title[0]) { #ifdef FEATURE_KAZAN_HOTLIST if (parentItemIndex == 0) DlgHotTree_AddTreeItem(NULL, me->title, me->href, (HTREEITEM) TVI_LAST, DlgHotTree_GetWebPageBitmapIndex(), DlgHotTree_GetHotlistTreeViewWindow(), me->bVisible); else DlgHotTree_AddTreeItem(parentTreeItem[parentItemIndex - 1], me->title, me->href, (HTREEITEM) TVI_LAST, DlgHotTree_GetWebPageBitmapIndex(), DlgHotTree_GetHotlistTreeViewWindow(), me->bVisible); #else Hash_Add(me->hash_stack[me->hash_table_index], me->href, me->title, NULL); #endif } me->bHaveAnchor = FALSE; } } break; case HTML_H3: { if (me->bHaveAnchor) { if (me->title[0]) { #ifdef FEATURE_KAZAN_HOTLIST if (parentItemIndex == 0) DlgHotTree_AddTreeItem(NULL, me->title, me->href, (HTREEITEM) TVI_LAST, DlgHotTree_GetWebPageBitmapIndex(), DlgHotTree_GetHotlistTreeViewWindow(), me->bVisible); else DlgHotTree_AddTreeItem(parentTreeItem[parentItemIndex - 1], me->title, me->href, (HTREEITEM) TVI_LAST, DlgHotTree_GetWebPageBitmapIndex(), DlgHotTree_GetHotlistTreeViewWindow(), me->bVisible); #else Hash_Add(me->hash_stack[me->hash_table_index], me->href, me->title, NULL); #endif } me->bHaveAnchor = FALSE; } me->bHaveHeader = FALSE; memset(me->title, 0, TITLE_LEN + 1); me->lenTitle = 0; me->bInHeader = TRUE; #ifdef FEATURE_KAZAN_HOTLIST if (present[HTML_HEADER_VISIBLE] && (strcmp(value[HTML_HEADER_VISIBLE], "1") == 0)) { me->bVisible = TRUE; } else { me->bVisible = FALSE; } #endif break; } case HTML_A: { if (me->bHaveAnchor) { if (me->title[0]) { #ifdef FEATURE_KAZAN_HOTLIST if (parentItemIndex == 0) DlgHotTree_AddTreeItem(NULL, me->title, me->href, (HTREEITEM) TVI_LAST, DlgHotTree_GetWebPageBitmapIndex(), DlgHotTree_GetHotlistTreeViewWindow(), me->bVisible); else DlgHotTree_AddTreeItem(parentTreeItem[parentItemIndex - 1], me->title, me->href, (HTREEITEM) TVI_LAST, DlgHotTree_GetWebPageBitmapIndex(), DlgHotTree_GetHotlistTreeViewWindow(), me->bVisible); #else Hash_Add(me->hash_stack[me->hash_table_index], me->href, me->title, NULL); #endif } me->bHaveAnchor = FALSE; } if (present[HTML_A_HREF]) { GTR_strncpy(me->href, value[HTML_A_HREF], MAX_URL_STRING); HTSimplify(me->href); } memset(me->title, 0, TITLE_LEN + 1); me->lenTitle = 0; me->bInAnchor = TRUE; me->bHaveAnchor = FALSE; #ifdef FEATURE_KAZAN_HOTLIST if (present[HTML_A_VISIBLE] && (strcmp(value[HTML_A_VISIBLE], "1") == 0)) { me->bVisible = TRUE; } else { me->bVisible = FALSE; } #endif break; } } } /* End Element ** ----------- ** */ PRIVATE void HTHotList_end_element(HTStructured * me, int element_number) { char *full_address; char mycopy[MAX_URL_STRING + 1]; char *stripped; switch (element_number) { case HTML_DL: { if (me->bHaveAnchor) { if (me->title[0]) { #ifdef FEATURE_KAZAN_HOTLIST if (parentItemIndex == 0) DlgHotTree_AddTreeItem(NULL, me->title, me->href, (HTREEITEM) TVI_LAST, DlgHotTree_GetWebPageBitmapIndex(), DlgHotTree_GetHotlistTreeViewWindow(), me->bVisible); else DlgHotTree_AddTreeItem(parentTreeItem[parentItemIndex - 1], me->title, me->href, (HTREEITEM) TVI_LAST, DlgHotTree_GetWebPageBitmapIndex(), DlgHotTree_GetHotlistTreeViewWindow(), me->bVisible); #else Hash_Add(me->hash_stack[me->hash_table_index], me->href, me->title, NULL); #endif } me->bHaveAnchor = FALSE; } #ifdef FEATURE_KAZAN_HOTLIST if (parentItemIndex > 0) { parentItemIndex--; } #endif if (me->hash_table_index > 0) { me->hash_table_index--; } } break; case HTML_H3: { if (me->title[0]) me->bHaveHeader = TRUE; me->bInHeader = FALSE; } break; case HTML_A: /* First get the full URL */ if (me->href) { GTR_strncpy(mycopy, me->href, MAX_URL_STRING); stripped = HTStrip(mycopy); if (stripped) { full_address = HTParse(stripped, me->base_url, PARSE_ACCESS | PARSE_HOST | PARSE_PATH | PARSE_PUNCTUATION | PARSE_ANCHOR); if (full_address) { GTR_strncpy(me->href, full_address, MAX_URL_STRING); GTR_FREE(full_address); me->bHaveAnchor = TRUE; } } } me->bInAnchor = FALSE; break; } } /* Expanding entities ** ------------------ ** */ PRIVATE void HTHotList_put_entity(HTStructured * me, int entity_number) { } /* Free an HTML object ** ------------------- ** */ PRIVATE void HTHotList_free(HTStructured * me) { if (me->bHaveAnchor) { if (me->title[0]) { #ifdef FEATURE_KAZAN_HOTLIST if (parentItemIndex == 0) DlgHotTree_AddTreeItem(NULL, me->title, me->href, (HTREEITEM) TVI_LAST, DlgHotTree_GetWebPageBitmapIndex(), DlgHotTree_GetHotlistTreeViewWindow(), me->bVisible); else DlgHotTree_AddTreeItem(parentTreeItem[parentItemIndex - 1], me->title, me->href, (HTREEITEM) TVI_LAST, DlgHotTree_GetWebPageBitmapIndex(), DlgHotTree_GetHotlistTreeViewWindow(), me->bVisible); #else Hash_Add(me->hash_stack[me->hash_table_index], me->href, me->title, NULL); #endif } me->bHaveAnchor = FALSE; } GTR_FREE(me); } PRIVATE void HTHotList_abort(HTStructured * me, HTError e) { HTHotList_free(me); } /* Structured Object Class ** ----------------------- */ PRIVATE CONST HTStructuredClass HTHotList = /* As opposed to print etc */ { "HTMLToHotList", HTHotList_free, HTHotList_abort, HTHotList_put_character, HTHotList_put_string, HTHotList_write, HTHotList_start_element, HTHotList_end_element, HTHotList_put_entity, NULL, NULL }; /* HTConverter from HTML to TeX Stream ** ------------------------------------------ ** */ PUBLIC HTStream *HTMLToHotList(struct Mwin *tw, HTRequest * request, void *param, HTFormat input_format, HTFormat output_format, HTStream * output_stream) { HTStructured *me = (HTStructured *) GTR_CALLOC(1, sizeof(*me)); if (me) { GTR_strncpy(me->base_url, request->destination->szActualURL, MAX_URL_STRING); me->bInAnchor = FALSE; me->bHaveAnchor = FALSE; me->bInHeader = FALSE; me->bHaveHeader = FALSE; #ifdef FEATURE_KAZAN_HOTLIST me->bVisible = FALSE; #endif me->hash_table_index = 0; me->hash_stack[0] = &gHotList; me->isa = (HTStructuredClass *) & HTHotList; me->dtd = &HTMLP_dtd; return SGML_new(tw, &HTMLP_dtd, me, request); } else { return NULL; } } struct Params_HotList_Load { HTRequest *request; /* Used internally */ int status; }; static int HotList_Load_Async(struct Mwin *tw, int nState, void **ppInfo) { struct Params_HotList_Load *pParams; struct Params_LoadAsync *p2; pParams = *ppInfo; switch (nState) { case STATE_INIT: p2 = GTR_MALLOC(sizeof(*p2)); p2->request = pParams->request; p2->pStatus = &pParams->status; bHotListLoading = TRUE; Async_DoCall(HTLoadDocument_Async, p2); return STATE_OTHER; case STATE_OTHER: case STATE_ABORT: bHotListLoading = FALSE; Dest_DestroyDest(pParams->request->destination); HTRequest_delete(pParams->request); return STATE_DONE; } XX_Assert((0), ("Function called with illegal state: %d", nState)); return STATE_DONE; } #ifdef FEATURE_KAZAN_HOTLIST /**************************************************************************** * * FUNCTION: HotList_IsLoading() * * PURPOSE: Returns the state of the asynchronous hotlist loading * procedure. This is used to disable the hotlist menu * item while the hotlist file is being read. The hotlist * is written to the filesystem synchronously. * ****************************************************************************/ BOOL HotList_IsLoading(void) { return bHotListLoading; } #endif /* FEATURE_KAZAN_HOTLIST */ void HotList_Init(void) { HTRequest *request; char url[MAX_URL_STRING + 1]; struct Params_HotList_Load *phll; struct DestInfo *pDest; #ifdef FEATURE_KAZAN_HOTLIST int idx; #endif #ifdef WIN32 char path[_MAX_PATH]; PREF_GetPathToHotlistFile(path); FixPathName(path); strcpy(url, "file:///"); strcat(url, path); #endif #ifdef FEATURE_KAZAN_HOTLIST /* Initialize the array of level pointers. */ parentItemIndex = 0; for (idx = 0; idx < MAX_HOTLIST_NESTING + 1; idx++) { parentTreeItem[idx] = NULL; } #endif #ifdef MAC #include "resequ.h" Str255 filename; strcpy(url, "file:///"); strcat(url, vv_Application); GetIndString(filename, OEM_FILES_STR_LIST, OEM_HLISTNAME_STR); p2cstr(filename); strcat(url, " "); strcat(url, filename); PathNameFromDirID (MacGlobals.prefFldrDirID, MacGlobals.prefFldrVRefNum, url + 8); FixPathName(url + 8); #endif #ifdef UNIX char path[_MAX_PATH]; strcpy(url, "file://"); strcat(url, gPrefs.szHotListFile); #endif memset(&gHotListTable, 0, sizeof(hotlist_stack_table)); #ifndef FEATURE_KAZAN_HOTLIST Hash_Init(&gHotList); gHotListTable.hotlist_stack_index = 0; gHotListTable.hotlist_stack[gHotListTable.hotlist_stack_index] = &gHotList; gHotListTable.hotlist_menu_index = 0; #endif pDest = Dest_CreateDest(url); if (pDest) { request = HTRequest_new(); HTFormatInit(request->conversions); request->output_format = HTAtom_for("www/hotlist"); request->destination = pDest; phll = GTR_MALLOC(sizeof(*phll)); phll->request = request; Async_StartThread(HotList_Load_Async, phll, NULL); } } #ifdef FEATURE_KAZAN_HOTLIST static void WriteEnterSubMenu(FILE *fp, int level) { int j; for (j = 0; j < level; j++) fprintf(fp, " "); fprintf(fp, "