home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libmisc / shist.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  30.8 KB  |  1,130 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20.     Session History module
  21.  
  22.     Public Functions
  23.         void         SHIST_InitSession(MWContext * ctxt);
  24.         void         SHIST_AddDocument(MWContext * ctxt, char * name, char * url,
  25.                                void * loc);
  26.         const char * SHIST_GetNext(MWContext * ctxt);
  27.         const char * SHIST_GetPrevious(MWContext * ctxt);
  28.         const char * SHIST_GetEntry(MWContext * ctxt, int entry_number);
  29.         int          SHIST_CanGoBack(MWContext * ctxt);
  30.         int          SHIST_CanGoForward(MWContext * ctxt);
  31. */
  32.  
  33. /*#define HAS_FE*/
  34.  
  35. #include "shist.h"
  36.  
  37. #include "libi18n.h"
  38.  
  39. #include "hotlist.h"
  40. #include "net.h"
  41. #include "xp.h"
  42.  
  43. #if !defined(XP_MAC) && !defined(XP_WIN32)    /* macOS doesn't need this anymore... nor does Windows */
  44.     #include "bkmks.h"
  45. #endif
  46.  
  47. #ifdef EDITOR
  48. #include "edt.h" /* for EDT_IS_EDITOR macro */
  49. extern char *XP_NEW_DOC_URL;
  50. extern char *XP_NEW_DOC_NAME;
  51. #include "xpgetstr.h"
  52. #endif
  53.  
  54. #include "libmocha.h"
  55. #include "glhist.h"
  56.  
  57. static int32 unique_id;
  58.  
  59. PRIVATE int shist_update_FE(MWContext * ctxt);
  60.  
  61.  
  62. PUBLIC History_entry *
  63. SHIST_HoldEntry (History_entry * entry)
  64. {
  65.     if (entry)
  66.         entry->ref_count++;
  67.     return entry;
  68. }
  69.  
  70. PUBLIC void
  71. SHIST_FreeHistoryEntry (MWContext * ctxt, History_entry * entry)
  72. {
  73.     if(entry && --entry->ref_count == 0)
  74.       {
  75.         if(entry->title)
  76.             XP_FREE (entry->title);
  77.         if(entry->address)
  78.             XP_FREE(entry->address);
  79.         if(entry->content_name)
  80.             XP_FREE(entry->content_name);
  81.         if(entry->referer)
  82.             XP_FREE(entry->referer);
  83.     
  84.         if(entry->post_data_is_file && entry->post_data)
  85.             XP_FileRemove(entry->post_data, xpFileToPost);
  86.         if(entry->post_data)
  87.             XP_FREE(entry->post_data);
  88.         if(entry->post_headers)
  89.             XP_FREE(entry->post_headers);
  90.             XP_FREE(entry->key_cipher);
  91.             XP_FREE(entry->key_issuer);
  92.             XP_FREE(entry->key_subject);
  93.         if(entry->refresh_url)
  94.             XP_FREE(entry->refresh_url);
  95.         if(entry->wysiwyg_url)
  96.             XP_FREE(entry->wysiwyg_url);
  97.         if(entry->page_services_url)
  98.             XP_FREE(entry->page_services_url);
  99.  
  100.         if(entry->savedData.FormList)
  101.             LO_FreeDocumentFormListData(ctxt, entry->savedData.FormList); 
  102.  
  103.         if(entry->savedData.EmbedList)
  104.             LO_FreeDocumentEmbedListData(ctxt, entry->savedData.EmbedList); 
  105.  
  106.         if(entry->savedData.Grid)
  107.             LO_FreeDocumentGridData(ctxt, entry->savedData.Grid); 
  108.  
  109.         if(entry->savedData.Window)
  110.             LM_DropSavedWindow(ctxt, entry->savedData.Window);
  111.         if(entry->savedData.OnLoad)
  112.             PA_FREE(entry->savedData.OnLoad);
  113.         if(entry->savedData.OnUnload)
  114.             PA_FREE(entry->savedData.OnUnload);
  115.         if(entry->savedData.OnFocus)
  116.             PA_FREE(entry->savedData.OnFocus);
  117.         if(entry->savedData.OnBlur)
  118.             PA_FREE(entry->savedData.OnBlur);
  119.         if(entry->savedData.OnHelp)
  120.             PA_FREE(entry->savedData.OnHelp);
  121.         if(entry->savedData.OnMouseOver)
  122.             PA_FREE(entry->savedData.OnMouseOver);
  123.         if(entry->savedData.OnMouseOut)
  124.             PA_FREE(entry->savedData.OnMouseOut);
  125.         if(entry->savedData.OnDragDrop)
  126.             PA_FREE(entry->savedData.OnDragDrop);
  127.         if(entry->savedData.OnMove)
  128.             PA_FREE(entry->savedData.OnMove);
  129.         if(entry->savedData.OnResize)
  130.             PA_FREE(entry->savedData.OnResize);
  131.  
  132.  
  133.         XP_FREE(entry);
  134.       }
  135. }
  136.  
  137. PUBLIC History_entry *
  138. SHIST_CreateHistoryEntry (URL_Struct * URL_s, char * title)
  139. {
  140.     History_entry * new_entry;
  141.  
  142.     if(!URL_s)
  143.         return(NULL);
  144.  
  145.     new_entry = XP_NEW(History_entry);
  146.  
  147.     if(!new_entry)
  148.         return(NULL);
  149.  
  150.     memset(new_entry, 0, sizeof(History_entry));
  151.  
  152.     new_entry->ref_count = 1;
  153.     new_entry->unique_id = ++unique_id;
  154.     new_entry->history_num = URL_s->history_num;
  155.  
  156.     new_entry->method         = URL_s->method;
  157.     new_entry->is_binary      = URL_s->is_binary;
  158.     new_entry->is_active      = URL_s->is_active;
  159.     new_entry->is_netsite     = URL_s->is_netsite;
  160.     new_entry->last_modified  = URL_s->last_modified;
  161.     new_entry->post_data_size = URL_s->post_data_size;
  162.     new_entry->post_data_is_file = URL_s->post_data_is_file;
  163.     new_entry->security_on    = URL_s->security_on;
  164.     new_entry->key_size       = URL_s->key_size;
  165.     new_entry->key_secret_size= URL_s->key_secret_size;
  166.  
  167.     new_entry->refresh        = URL_s->refresh;
  168.  
  169.     if(URL_s->memory_copy)
  170.         new_entry->transport_method = SHIST_CAME_FROM_MEMORY_CACHE;
  171.     else if(URL_s->cache_file)
  172.         new_entry->transport_method = SHIST_CAME_FROM_DISK_CACHE;
  173.     else
  174.         new_entry->transport_method = SHIST_CAME_FROM_NETWORK;
  175.  
  176.     StrAllocCopy(new_entry->referer,      URL_s->referer);
  177.     StrAllocCopy(new_entry->refresh_url,  URL_s->refresh_url);
  178.     StrAllocCopy(new_entry->wysiwyg_url,  URL_s->wysiwyg_url);
  179.  
  180.     StrAllocCopy(new_entry->key_cipher,   URL_s->key_cipher);
  181.  
  182.     /* XXX obsolete */
  183.     StrAllocCopy(new_entry->key_issuer,   URL_s->key_issuer);
  184.     StrAllocCopy(new_entry->key_subject,  URL_s->key_subject);
  185.  
  186.     StrAllocCopy(new_entry->title,        title);
  187.     StrAllocCopy(new_entry->address,      URL_s->address);
  188.     StrAllocCopy(new_entry->content_name, URL_s->content_name);
  189.     StrAllocCopy(new_entry->post_data,    URL_s->post_data);
  190.     StrAllocCopy(new_entry->post_headers, URL_s->post_headers);
  191.  
  192.     StrAllocCopy(new_entry->page_services_url, URL_s->page_services_url);
  193.     StrAllocCopy(new_entry->etag, URL_s->etag);
  194.  
  195.     return(new_entry);
  196. }
  197.  
  198.  
  199. PUBLIC URL_Struct *
  200. SHIST_CreateURLStructFromHistoryEntry(MWContext * ctxt, History_entry * entry)
  201. {
  202.     URL_Struct * URL_s;
  203.     if(!entry)
  204.         return(NULL);
  205.  
  206.     URL_s = NET_CreateURLStruct(entry->address, NET_DONT_RELOAD);
  207.     if(!URL_s)
  208.         return(NULL);
  209.  
  210.     URL_s->method = entry->method;
  211.     StrAllocCopy(URL_s->content_name, entry->content_name);
  212.     StrAllocCopy(URL_s->post_data, entry->post_data);
  213.     StrAllocCopy(URL_s->post_headers, entry->post_headers);
  214.  
  215.     StrAllocCopy(URL_s->key_cipher,   entry->key_cipher);
  216.     StrAllocCopy(URL_s->referer,      entry->referer);
  217.     StrAllocCopy(URL_s->refresh_url,  entry->refresh_url);
  218.     StrAllocCopy(URL_s->wysiwyg_url,  entry->wysiwyg_url);
  219.  
  220.     /* XXX obsolete */
  221.     StrAllocCopy(URL_s->key_issuer,   entry->key_issuer);
  222.     StrAllocCopy(URL_s->key_subject,  entry->key_subject);
  223.     StrAllocCopy(URL_s->etag,  entry->etag);
  224.  
  225.     URL_s->refresh        = entry->refresh;
  226.     URL_s->security_on    = entry->security_on;
  227.     URL_s->key_size       = entry->key_size;
  228.     URL_s->key_secret_size= entry->key_secret_size;
  229.  
  230.     URL_s->post_data_size = entry->post_data_size;
  231.     URL_s->post_data_is_file = entry->post_data_is_file;
  232.     URL_s->position_tag   = entry->position_tag;
  233.     URL_s->history_num    = SHIST_GetIndex(&ctxt->hist, entry);
  234.     URL_s->savedData      = entry->savedData; /* copy whole struct */
  235.     URL_s->is_binary      = entry->is_binary;
  236.     URL_s->is_active      = entry->is_active;
  237.     URL_s->is_netsite     = entry->is_netsite;
  238.     URL_s->last_modified  = entry->last_modified;
  239.  
  240.     return(URL_s);
  241. }
  242.  
  243. URL_Struct *
  244. SHIST_CreateWysiwygURLStruct(MWContext * ctxt, History_entry * entry)
  245. {
  246.     URL_Struct *URL_s;
  247.  
  248.     URL_s = SHIST_CreateURLStructFromHistoryEntry(ctxt, entry);
  249.     if (URL_s && URL_s->wysiwyg_url)
  250.       {
  251.         StrAllocCopy(URL_s->address, URL_s->wysiwyg_url);
  252.       }
  253.     return URL_s;
  254. }
  255.  
  256. /*
  257.  * Returns NULL if the entry cannot be a hotlist item (form submission).
  258.  */
  259.  
  260. #if !defined(XP_MAC) && !defined(XP_WIN32)    /* macOS doesn't need this anymore -- we're 100% RDF! so is windows! */
  261.  
  262. BM_Entry* SHIST_CreateHotlistStructFromHistoryEntry(History_entry * h)
  263. {
  264.     BM_Entry* hs = NULL;
  265.     if ((h == NULL) || h->post_data)    /* Cannot make form submission into bookmarks */
  266.         return NULL;
  267.     
  268.     /* if title is empty make the title the URL in the form www.XXX...YYY.html */
  269.     if ( *h->title )
  270.         hs = BM_NewUrl( h->title, h->address, NULL, h->last_access);
  271.     else
  272.     {
  273.         /* Strip off the protocol info (eg, http://) */
  274.         char trunkedAddress [HIST_MAX_URL_LEN + 1];
  275.         char* strippedAddress = SHIST_StripProtocol ( h->address );
  276.         
  277.         /* truncate it */
  278.         INTL_MidTruncateString ( 0, strippedAddress, trunkedAddress, HIST_MAX_URL_LEN );
  279.         hs = BM_NewUrl( trunkedAddress, h->address, NULL, h->last_access);
  280.     }
  281.     
  282.     return hs;
  283.     
  284. } /* SHIST_CreateHotlistStructFromHistoryEntry */
  285. #endif
  286.  
  287. /*
  288.  * SHIST_StripProtocol
  289.  *
  290.  * Given a URL (eg, http://foo.com/foo/bar), strips off the protocol part. This does not
  291.  * create a new string but returns an index into the original URL.
  292.  */
  293.  
  294. char* SHIST_StripProtocol ( char* inURL )
  295. {
  296.     char* startOfAddress;
  297.     
  298.     if ( !inURL )
  299.         return NULL;
  300.  
  301.     startOfAddress = strchr ( inURL, ':' );        /* find the colon */
  302.     if ( startOfAddress ) 
  303.     {
  304.         if ( *(startOfAddress+1) == '/' )
  305.             if ( *(startOfAddress+2) == '/' )    /* http://foo, ftp://foo ... */
  306.                 startOfAddress += 3;
  307.             else                                /* can this case ever exist? */
  308.                 startOfAddress += 2;
  309.         else                                    /* mailto:foo or news:foo */
  310.             startOfAddress++;
  311.     }
  312.     else                                        /* no colons, should never happen... */
  313.         startOfAddress = inURL;            
  314.  
  315.     return startOfAddress;
  316.     
  317. } /* SHIST_StripProtocol */
  318.  
  319.  
  320. /* ---
  321.  
  322.    Name: shist_update_FE 
  323.    Parameters:
  324.     ctxt - (read) session context
  325.    Returns:
  326.         status from frontend 
  327.    Description:
  328.         The history list has changed.  Make sure the forward / back button
  329.         on the front end are in sync.
  330.  
  331. --- */
  332. PRIVATE int
  333. shist_update_FE(MWContext * ctxt)
  334. {
  335.     int status = TRUE;
  336.  
  337. #ifdef XP_UNIX
  338.  
  339.     if ((ctxt->is_grid_cell)&&(ctxt->grid_parent != NULL))
  340.     {
  341.     status = shist_update_FE(ctxt->grid_parent);
  342.     }
  343.  
  344.     if(ctxt->hist.num_entries > ctxt->hist.cur_doc)
  345.     {
  346.     status = FE_EnableForwardButton(ctxt);
  347.     }
  348.     else
  349.     {
  350.     if ((ctxt->grid_children != NULL)&&(LO_GridCanGoForward(ctxt)))
  351.     {
  352.         status = FE_EnableForwardButton(ctxt);
  353.     }
  354.     else
  355.     {
  356.         status = FE_DisableForwardButton(ctxt);
  357.     }
  358.     }
  359.  
  360.     if(status < 0)
  361.         return(status);
  362.  
  363.     if(ctxt->hist.cur_doc > 1)
  364.     {
  365.     status = FE_EnableBackButton(ctxt);
  366.     }
  367.     else
  368.     {
  369.     if ((ctxt->grid_children != NULL)&&(LO_GridCanGoBackward(ctxt)))
  370.     {
  371.         status = FE_EnableBackButton(ctxt);
  372.     }
  373.     else
  374.     {
  375.         status = FE_DisableBackButton(ctxt);
  376.     }
  377.     }
  378.  
  379. #endif /* XP_UNIX */
  380.  
  381.     return(status);
  382.  
  383. } /* shist_update_FE */
  384.  
  385.  
  386. /* ---
  387.  
  388.    Name: SHIST_InitSession
  389.    Parameters:
  390.     ctxt - (modified) session context
  391.    Returns:
  392.         void
  393.    Description:
  394.         Initialize the session history module.  Since we are initializing
  395.         assume there is not a current history list that we need to free.
  396.  
  397. --- */
  398. PUBLIC void
  399. SHIST_InitSession(MWContext * ctxt)
  400. {
  401.  
  402.     if(!ctxt)
  403.         return;
  404.  
  405.     ctxt->hist.cur_doc  = 0;
  406.     ctxt->hist.cur_doc_ptr  = 0;
  407.     ctxt->hist.list_ptr = XP_ListNew();
  408.     ctxt->hist.num_entries = 0;
  409.     ctxt->hist.max_entries = -1;
  410.     shist_update_FE(ctxt);
  411.  
  412. #ifdef JAVA
  413.     PR_INIT_CLIST(&ctxt->javaContexts);
  414. #if defined(XP_PC) || defined(XP_UNIX)
  415.     {
  416.         char *ev = getenv("NS_HISTORY_LIMIT");
  417.         int limit = 50;
  418.         if (ev && ev[0]) {
  419.             limit = atoi(ev);
  420.             if ((limit < 3) || (limit >= 32767)) {
  421.                 limit = 50;
  422.             }
  423.         }
  424.         ctxt->hist.max_entries = limit;
  425.     }
  426. #endif /* PC or UNIX */
  427. #endif /* JAVA */
  428.  
  429. } /* SHIST_InitSession */
  430.  
  431. PUBLIC void
  432. SHIST_EndSession(MWContext * ctxt)
  433. {
  434.     XP_List * list_ptr = ctxt->hist.list_ptr;
  435.     History_entry * old_entry;
  436.  
  437.     while((old_entry = (History_entry *) XP_ListRemoveTopObject(list_ptr))!=0)
  438.         SHIST_FreeHistoryEntry(ctxt, old_entry);
  439.  
  440.     XP_ListDestroy(ctxt->hist.list_ptr);
  441.  
  442.     ctxt->hist.list_ptr = 0;
  443.     ctxt->hist.cur_doc = 0;
  444.     ctxt->hist.cur_doc_ptr = 0;
  445. }
  446.  
  447. /* duplicate the given entry
  448.  */
  449. PUBLIC History_entry *
  450. SHIST_CloneEntry(History_entry * old_entry)
  451. {
  452.     History_entry *new_entry = NULL;
  453.  
  454.     if(old_entry == NULL)
  455.     return NULL;
  456.  
  457.     new_entry = XP_NEW_ZAP(History_entry);
  458.  
  459.     if(new_entry == NULL)
  460.     return NULL;
  461.  
  462.     StrAllocCopy(new_entry->title, old_entry->title);
  463.     StrAllocCopy(new_entry->address, old_entry->address);
  464.     StrAllocCopy(new_entry->content_name, old_entry->content_name);
  465.     StrAllocCopy(new_entry->referer, old_entry->referer);
  466.     StrAllocCopy(new_entry->post_data, old_entry->post_data);
  467.     StrAllocCopy(new_entry->post_headers, old_entry->post_headers);
  468.  
  469.     new_entry->unique_id = ++unique_id;
  470.     new_entry->post_data_size = old_entry->post_data_size;
  471.     new_entry->post_data_is_file = old_entry->post_data_is_file;
  472.     new_entry->method         = old_entry->method;
  473.     new_entry->is_binary      = old_entry->is_binary;
  474.     new_entry->is_active      = old_entry->is_active;
  475.     new_entry->is_netsite     = old_entry->is_netsite;
  476.     new_entry->position_tag   = old_entry->position_tag;
  477.     new_entry->security_on    = old_entry->security_on;
  478.     new_entry->key_size       = old_entry->key_size;
  479.     new_entry->key_secret_size= old_entry->key_secret_size;
  480.  
  481.     new_entry->last_modified  = old_entry->last_modified;
  482.  
  483.     StrAllocCopy(new_entry->key_cipher,   old_entry->key_cipher);
  484.     StrAllocCopy(new_entry->key_issuer,   old_entry->key_issuer);
  485.     StrAllocCopy(new_entry->key_subject,  old_entry->key_subject);
  486.  
  487.     StrAllocCopy(new_entry->page_services_url, old_entry->page_services_url);
  488.  
  489.     new_entry->ref_count = 1;
  490.     return new_entry;
  491.  
  492. }
  493.  
  494.  
  495.  
  496. /* copys all the session data from the old context into the
  497.  * new context.  Does not effect data in old_context session history
  498.  *
  499.  * if new_context has not had SHIST_InitSession called for it
  500.  * it will be called to initalize it.
  501.  */
  502. PUBLIC void
  503. SHIST_CopySession(MWContext * new_context, MWContext * old_context)
  504. {
  505.     XP_List * list_ptr;
  506.     History_entry *new_entry, *old_entry;
  507.     int x, y;
  508.  
  509.     if(!new_context || !old_context)
  510.     return;
  511.  
  512.     if(!new_context->hist.list_ptr)
  513.     SHIST_InitSession(new_context);
  514.  
  515.     list_ptr = old_context->hist.list_ptr;
  516.  
  517.     x = XP_ListCount(new_context->hist.list_ptr);
  518.     y = XP_ListCount(old_context->hist.list_ptr);
  519.  
  520.     while((old_entry = (History_entry *) XP_ListNextObject(list_ptr))!=0) {
  521. #ifdef EDITOR
  522.         /* Skip new document entries when copying from Editor context */
  523.         if ( EDT_IS_EDITOR(old_context) && old_entry->address && 
  524.              (0 == XP_STRCMP(old_entry->address, XP_NEW_DOC_NAME) ||
  525.               0 == XP_STRCMP(old_entry->address, XP_NEW_DOC_URL)) )
  526.         {
  527.             continue;            
  528.         }
  529. #endif
  530.         new_entry = SHIST_CloneEntry(old_entry);
  531.         if(!new_entry)
  532.         continue;
  533.  
  534.     XP_ListAddObjectToEnd(new_context->hist.list_ptr, SHIST_HoldEntry(new_entry));
  535.     }
  536.  
  537.     new_context->hist.num_entries = XP_ListCount(new_context->hist.list_ptr);
  538.     new_context->hist.max_entries = old_context->hist.max_entries;
  539.     if(new_context->hist.num_entries > 0) {
  540.     new_context->hist.cur_doc = 1;
  541.     new_context->hist.cur_doc_ptr = 
  542.         (History_entry *) XP_ListGetObjectNum(new_context->hist.list_ptr,
  543.                           new_context->hist.cur_doc);
  544.     }
  545.  
  546.     shist_update_FE(new_context);
  547. }
  548.  
  549. /* ---
  550.  
  551.    Name: SHIST_AddDocument
  552.    Parameters:
  553.     ctxt - (modified) session context
  554.         name - (read) name of document to add
  555.         url  - (read) url of document to add
  556.         loc  - (read) location in current document for backtracking later
  557.    Returns:
  558.         void
  559.    Description:
  560.         Add a document after the current document in the history list.  If
  561.         there were other documents after the current document free their
  562.         records cuz we won't have any logical way to get to them via the
  563.         history list.
  564.  
  565.         We need to save some sort of location information about the current
  566.         document so if we backtrack to it later we know what to show to the
  567.         user.
  568.  
  569. --- */         
  570. PUBLIC void
  571. SHIST_AddDocument(MWContext * ctxt, History_entry * new_entry)
  572. {
  573.     int count;
  574. /*    XP_List * list_ptr = ctxt->hist.list_ptr;*/
  575.     History_entry * old_entry;
  576.     
  577.     if(!ctxt || !new_entry)
  578.         return;
  579. #ifdef EDITOR
  580.     /* If not done, get our strings out of XP_MSG.I resources 
  581.        (Probably done during first NET_GetURL() call, but lets be sure)
  582.     */
  583.     if (XP_NEW_DOC_URL == NULL) {
  584.         StrAllocCopy(XP_NEW_DOC_URL, "about:editfilenew");
  585.         /* StrAllocCopy(XP_NEW_DOC_URL, XP_GetString(XP_NEW_EDIT_DOC_URL) ); */
  586.     }
  587.     if (XP_NEW_DOC_NAME == NULL) {
  588.         StrAllocCopy(XP_NEW_DOC_NAME, "file:///Untitled" );
  589.         /* StrAllocCopy(XP_NEW_DOC_NAME, XP_GetString(XP_NEW_EDIT_DOC_NAME) );*/
  590.     }
  591.     /* Detect attempts to add "about:editfilenew"
  592.        history entry and replace with "file:///Untitled".
  593.     */
  594.     if (new_entry->address && 
  595.         0 == XP_STRCMP(new_entry->address, XP_NEW_DOC_URL) )
  596.     {
  597.         XP_FREE(new_entry->address);
  598.         /* Remove title */
  599.         if(new_entry->title) {
  600.             XP_FREE(new_entry->title);
  601.             new_entry->title = NULL;   /* as long as we're XP_FREEing it, lets NULL it out... */
  602.         }
  603.         new_entry->address = XP_STRDUP(XP_NEW_DOC_NAME);
  604.         /* Leave title empty -- it will showup as "Untitled" in caption */
  605.         /* new_entry->title = XP_STRDUP(XP_NEW_DOC_NAME); */
  606.         /* Unlikely, but abort if no name generated */
  607.         if (!new_entry->address)
  608.           {
  609.             SHIST_FreeHistoryEntry(ctxt, new_entry);
  610.             return;
  611.           }
  612.     }
  613.  
  614. #endif
  615.  
  616.     /* If this new entry doesn't have a history_num, and it has the same
  617.        URL as the topmost history entry, then don't add this to the
  618.        history - just use the old one. */
  619.     old_entry = SHIST_GetCurrent(&ctxt->hist);
  620.     if (old_entry &&
  621.         !new_entry->history_num &&
  622.         !old_entry->post_data && !new_entry->post_data &&
  623.         !XP_STRCMP(old_entry->address, new_entry->address))
  624.       {
  625.         /* don't add this one to the history */
  626.         SHIST_FreeHistoryEntry(ctxt, new_entry);
  627.         return;
  628.       }
  629.  
  630.     /* Only web browser windows record history - mail, news, composition,
  631.        etc windows do not.
  632.  
  633.        In a non-web-browser window, cause there to be exactly one entry
  634.        on the history list (there needs to be one, because many things
  635.        use the history to find out the current URL.)  Do this by emptying
  636.        out the list each time this is called - we will then add this entry
  637.        to then end of the now-empty list.
  638.      */
  639.     if (ctxt->type != MWContextBrowser && ctxt->type != MWContextPane &&
  640.         /* For mail and news windows, history_num is only non-zero when the
  641.            window is being resized - in which case, the only item on the
  642.            history has the same URL (right?) and we will copy the contents
  643.            of the new entry into the old, free the new entry, and not free
  644.            the form data that is in the old.  Gag. */
  645.         new_entry->history_num == 0)
  646.       {
  647.         XP_List * list_ptr = ctxt->hist.list_ptr;
  648.         History_entry * old_entry;
  649.  
  650.         while((old_entry = (History_entry *)XP_ListRemoveTopObject(list_ptr))
  651.               !=0)
  652.         {
  653.             SHIST_FreeHistoryEntry(ctxt, old_entry);
  654.         }
  655.         ctxt->hist.cur_doc = 0;
  656.         ctxt->hist.cur_doc_ptr = 0;
  657.       }
  658.  
  659.     /* If this entry doesn't have a URL in it, throw it away. */
  660.     if (!new_entry->address || !*new_entry->address)
  661.       {
  662.         SHIST_FreeHistoryEntry(ctxt, new_entry);
  663.         return;
  664.       }
  665.  
  666.     if(new_entry->history_num)
  667.       {
  668.         old_entry = (History_entry *) XP_ListGetObjectNum(ctxt->hist.list_ptr, 
  669.                                                           new_entry->history_num);
  670.  
  671.         /* make sure that we have the same entry in case something weird 
  672.          * happened
  673.          *
  674.          * @@@ approx match. should check post data
  675.          */
  676.         if(old_entry &&
  677.            (!XP_STRCMP(old_entry->address, new_entry->address) ||
  678.             old_entry->replace ||
  679.             (old_entry->wysiwyg_url &&
  680.              !XP_STRCMP(old_entry->wysiwyg_url, new_entry->address))))
  681.           {
  682.             if(old_entry->replace)
  683.               {
  684.                 StrAllocCopy(old_entry->title, new_entry->title);
  685.                 StrAllocCopy(old_entry->address, new_entry->address);
  686.                 StrAllocCopy(old_entry->post_data, new_entry->post_data);
  687.                 StrAllocCopy(old_entry->post_headers, new_entry->post_headers);
  688.  
  689.                 old_entry->post_data_size = new_entry->post_data_size;
  690.                 old_entry->post_data_is_file = new_entry->post_data_is_file;
  691.                 old_entry->method         = new_entry->method;
  692.                 old_entry->position_tag   = new_entry->position_tag;
  693.                 old_entry->is_binary      = new_entry->is_binary;
  694.                 old_entry->is_active      = new_entry->is_active;
  695.                 old_entry->is_netsite     = new_entry->is_netsite;
  696.  
  697.                 /* Unique identifier */
  698.                 old_entry->unique_id = ++unique_id;
  699.               }
  700.  
  701.             /* this stuff has the possibility of changing,
  702.              * so copy it
  703.              */
  704.             StrAllocCopy(old_entry->key_cipher,   new_entry->key_cipher);
  705.             StrAllocCopy(old_entry->key_issuer,   new_entry->key_issuer);
  706.             StrAllocCopy(old_entry->key_subject,  new_entry->key_subject);
  707.             StrAllocCopy(old_entry->referer,      new_entry->referer);
  708.             StrAllocCopy(old_entry->refresh_url,  new_entry->refresh_url);
  709.             StrAllocCopy(old_entry->wysiwyg_url,  new_entry->wysiwyg_url);
  710.             StrAllocCopy(old_entry->content_name, new_entry->content_name);
  711.  
  712.             old_entry->refresh          = new_entry->refresh;
  713.             old_entry->security_on      = new_entry->security_on;
  714.             old_entry->key_size         = new_entry->key_size;
  715.             old_entry->key_secret_size  = new_entry->key_secret_size;
  716.  
  717.  
  718.             old_entry->transport_method = new_entry->transport_method;
  719.             old_entry->last_modified  = new_entry->last_modified;
  720.             old_entry->last_access = time(NULL);
  721.  
  722.             ctxt->hist.cur_doc = new_entry->history_num;
  723.             ctxt->hist.cur_doc_ptr = old_entry;
  724.  
  725.             SHIST_FreeHistoryEntry(ctxt, new_entry);
  726.             shist_update_FE(ctxt);
  727.             return;
  728.           }
  729.         /* something went wrong. Add it to the end of the list
  730.          */
  731.       }
  732.  
  733.     new_entry->last_access = time(NULL);
  734.     
  735.     /* take 'em off from the end so we don't bust the XP_List layering */
  736.     for(count = XP_ListCount(ctxt->hist.list_ptr); count > ctxt->hist.cur_doc; count--) {
  737.         old_entry = (History_entry *) XP_ListRemoveEndObject(ctxt->hist.list_ptr);
  738.         SHIST_FreeHistoryEntry(ctxt, old_entry);
  739.     }
  740.  
  741.     /* if the history list is too long, shorten it by taking things off
  742.        the start of the list. */
  743.     if (ctxt->hist.max_entries > 0) {
  744.         while (ctxt->hist.cur_doc >= ctxt->hist.max_entries)
  745.         {
  746.             old_entry = (History_entry *)
  747.                 XP_ListRemoveTopObject(ctxt->hist.list_ptr);
  748.             SHIST_FreeHistoryEntry(ctxt, old_entry);
  749.             ctxt->hist.cur_doc--;
  750.         }
  751.     }
  752.  
  753.     /* add the new element to the end */    
  754.     XP_ListAddObjectToEnd(ctxt->hist.list_ptr, new_entry);
  755.     ctxt->hist.num_entries = XP_ListCount(ctxt->hist.list_ptr);
  756.  
  757.     ctxt->hist.cur_doc++;
  758.     ctxt->hist.cur_doc_ptr = (History_entry *) XP_ListGetObjectNum(ctxt->hist.list_ptr, 
  759.                                                  ctxt->hist.cur_doc);
  760.  
  761.     LO_CleanupGridHistory(ctxt);
  762.     if (ctxt->is_grid_cell)
  763.     {
  764.     LO_UpdateGridHistory(ctxt);
  765.     }
  766.  
  767.     shist_update_FE(ctxt);
  768.  
  769. } /* SHIST_AddDocument */
  770.  
  771. #if defined(DEBUG) && !defined(_WINDOWS)
  772. /* dump a history list to stdout */
  773. PUBLIC void
  774. SHIST_DumpHistory(MWContext * ctxt) 
  775. {
  776.     XP_List * list_ptr = ctxt->hist.list_ptr;
  777.     History_entry * entry;
  778.  
  779.     while((entry = (History_entry*) XP_ListNextObject(list_ptr)))
  780.       {
  781. #ifdef XP_UNIX 
  782.         printf("SHIST: cur_doc:%d      address:%s    \n", ctxt->hist.cur_doc, entry->address);
  783. #endif
  784.       }
  785. #ifdef XP_UNIX 
  786.     printf("---End of History List---\n");
  787. #endif
  788. } /* SHIST_DumpHistory */
  789. #endif /* DEBUG */
  790.  
  791.  
  792.  
  793. /* ---
  794.     Name: SHIST_GetPrevious
  795.     Return:
  796.          URL of previous document or NULL on failure
  797.     Parameters:
  798.          ctxt - (modified) window context
  799.     Description:
  800.         The entry returned should not be free'd by the caller
  801.  
  802.          calls FE functions to fix dimming of next and
  803.     previous buttons as needed.
  804.  
  805. --- */
  806. PUBLIC History_entry *
  807. SHIST_GetPrevious(MWContext * ctxt)
  808. {
  809.     /* check to make sure is a previous record */
  810.     if(!ctxt || ctxt->hist.cur_doc < 2)
  811.         return NULL;
  812.  
  813.     return((History_entry *) XP_ListGetObjectNum(ctxt->hist.list_ptr, ctxt->hist.cur_doc-1));
  814. }
  815.  
  816. PUBLIC History_entry *
  817. SHIST_GetCurrent(History * hist)
  818. {
  819.  
  820.     if(!hist)
  821.         return NULL;
  822.  
  823.     /* return URL */
  824.     return(hist->cur_doc_ptr);
  825.  
  826.  
  827. #if defined(XP_WIN) || defined(XP_MAC) || defined(XP_OS2)
  828. PUBLIC void
  829. SHIST_SetTitleOfCurrentDoc( MWContext *context )
  830. {
  831.      History_entry *  he;
  832.     URL_Struct *     pUrl;
  833.     XP_Bool hidden;
  834.  
  835.     if( !context )
  836.     {
  837.         return;
  838.     }
  839.     
  840.      he = SHIST_GetCurrent( &context->hist );
  841.     
  842.     if( he )
  843.     {
  844.         StrAllocCopy( he->title, context->title );
  845.  
  846.         /*
  847.          * This is the place where we set the title for *global* history hash records
  848.          * In addition to not making grid cells normal history entries we've added two 
  849.      * more types, js_dependent windows and the Netcaster window.  Yes, it's a hack
  850.      * but we're short on time.
  851.      */
  852.     hidden = context->is_grid_cell || context->js_parent || 
  853.         (context->name && !XP_STRCMP("Netcaster_SelectorTab", context->name));
  854.         pUrl = NET_CreateURLStruct( he->address, NET_DONT_RELOAD );
  855.         GH_UpdateURLTitle( pUrl, he->title, hidden);
  856.         NET_FreeURLStruct( pUrl );
  857.     }
  858. }
  859. #else
  860. PUBLIC void
  861. SHIST_SetTitleOfCurrentDoc(History * hist, char * title)
  862. {
  863.      History_entry * he = SHIST_GetCurrent(hist);
  864.     URL_Struct *pUrl;
  865.     
  866.     if( he )
  867.     {
  868.         StrAllocCopy(he->title, title);
  869.  
  870.         /*
  871.          * This is the place where we set the title for *global* history hash records
  872.          */
  873.         pUrl = NET_CreateURLStruct( he->address, NET_DONT_RELOAD );
  874.         GH_UpdateURLTitle( pUrl, he->title, FALSE );
  875.         NET_FreeURLStruct( pUrl );
  876.     }
  877. }
  878. #endif
  879.  
  880. PUBLIC void
  881. SHIST_SetCurrentDocFormListData(MWContext * context, void * form_data)
  882. {
  883.      History_entry * he = SHIST_GetCurrent(&context->hist);
  884.  
  885.     if(he)
  886.       {
  887.         he->savedData.FormList = form_data;
  888.       }
  889. }
  890.  
  891. PUBLIC void
  892. SHIST_SetCurrentDocEmbedListData(MWContext * context, void * embed_data)
  893. {
  894.      History_entry * he = SHIST_GetCurrent(&context->hist);
  895.  
  896.     if(he)
  897.       {
  898.         he->savedData.EmbedList = embed_data;
  899.       }
  900. }
  901.  
  902. PUBLIC void
  903. SHIST_SetCurrentDocGridData(MWContext * context, void * grid_data)
  904. {
  905.      History_entry * he = SHIST_GetCurrent(&context->hist);
  906.  
  907.     if(he)
  908.       {
  909.         he->savedData.Grid = grid_data;
  910.       }
  911. }
  912.  
  913. PUBLIC void
  914. SHIST_SetCurrentDocWindowData(MWContext * context, void *window_data)
  915. {
  916.      History_entry * he = SHIST_GetCurrent(&context->hist);
  917.  
  918.     if(he)
  919.       {
  920.         he->savedData.Window = window_data;
  921.       }
  922. }
  923.  
  924. PUBLIC void
  925. SHIST_SetPositionOfCurrentDoc(History * hist, int32 position_tag)
  926. {
  927.     History_entry * he = SHIST_GetCurrent(hist);    
  928.  
  929.     if(he)  
  930.       { 
  931.         he->position_tag = position_tag;
  932.       }
  933. }
  934.  
  935.  
  936.  
  937.  
  938. /* ---
  939.     Name: SHIST_GetNext
  940.     Return:
  941.          URL of next document or NULL on failure
  942.     Parameters:
  943.          ctxt - (modified) window context
  944.     Description:
  945.          The URL string should NOT be free'd by the user.  If they need
  946.     it for any length of time they should make their own copy.  If there
  947.     is no previous document return NULL.
  948.  
  949.          This function will set the "current" document pointer to the
  950.     document whose URL was just retreived.
  951.  
  952.          There needs to be a way to get the correct location out too and
  953.     pass it to whomever wants it. 
  954.  
  955.          Should probably call FE functions to fix dimming of next and
  956.     previous buttons as needed.
  957.  
  958. --- */
  959. PUBLIC History_entry *
  960. SHIST_GetNext(MWContext * ctxt)
  961. {
  962.     /* check to make sure is a next record */
  963.     if(!ctxt || ctxt->hist.num_entries <= ctxt->hist.cur_doc)
  964.         return NULL;
  965.  
  966.     return((History_entry *) XP_ListGetObjectNum(ctxt->hist.list_ptr, ctxt->hist.cur_doc+1));
  967.  
  968. } /* SHIST_GetNext */
  969.  
  970. /* ---
  971.  
  972.     Return TRUE if there is a previous record in the history
  973.     list we can go back to else FALSE
  974.  
  975. --- */
  976. PUBLIC int
  977. SHIST_CanGoBack(MWContext * ctxt)
  978. {
  979.     History *hist;
  980.  
  981.     hist = &ctxt->hist;
  982.  
  983.     /* check to make sure is a previous record */
  984.     if(!hist ||  hist->cur_doc < 2)
  985.     {
  986.     if ((ctxt->grid_children != NULL)&&(LO_GridCanGoBackward(ctxt)))
  987.     {
  988.         return TRUE;
  989.     }
  990.     return FALSE;
  991.     }
  992.  
  993.     return TRUE;
  994. }
  995.  
  996. /* ---
  997.  
  998.     Return TRUE if there is a next record in the history
  999.     list we can go forward to else FALSE
  1000.  
  1001. --- */
  1002. PUBLIC int
  1003. SHIST_CanGoForward(MWContext * ctxt)
  1004. {
  1005.     History *hist;
  1006.  
  1007.     hist = &ctxt->hist;
  1008.  
  1009.     /* check to make sure is a next record */
  1010.     if(!hist || hist->num_entries <= hist->cur_doc)
  1011.     {
  1012.     if ((ctxt->grid_children != NULL)&&(LO_GridCanGoForward(ctxt)))
  1013.     {
  1014.         return TRUE;
  1015.     }
  1016.     return FALSE;
  1017.     }
  1018.  
  1019.     return TRUE;
  1020. }
  1021.  
  1022.  
  1023. /* ---
  1024.  
  1025.   Return the URL for a document in the middle of the history list.
  1026.   entry_number is the zero based index of the entry to look up
  1027.   the current document pointers are updated appropriately
  1028.   returns NULL on failure or a string that the user should NOT
  1029.    free
  1030.  
  1031. --- */
  1032. PUBLIC History_entry * 
  1033. SHIST_GetEntry(History * hist, int entry_number)
  1034. {
  1035.     /* validate parameters */
  1036.     if(!hist)
  1037.         return NULL;
  1038.  
  1039.     /* return the current URL */
  1040.     return((History_entry *) XP_ListGetObjectNum(hist->list_ptr, entry_number+1));
  1041.  
  1042. } /* SHIST_GetEntry */
  1043.  
  1044. PUBLIC int
  1045. SHIST_GetIndex(History * hist, History_entry * entry)
  1046. {
  1047.     return(XP_ListGetNumFromObject(hist->list_ptr, entry));
  1048. }
  1049.  
  1050. PUBLIC History_entry *
  1051. SHIST_GetObjectNum(History * hist, int index)
  1052. {
  1053.     return((History_entry *)XP_ListGetObjectNum(hist->list_ptr, index));
  1054. }
  1055.  
  1056.  
  1057. /* sets the current doc pointer to the index specified in the call
  1058.  */
  1059. PUBLIC void
  1060. SHIST_SetCurrent(History * hist, int entry_number)
  1061. {
  1062.     hist->cur_doc = entry_number;
  1063.     hist->cur_doc_ptr = SHIST_GetObjectNum(hist, hist->cur_doc);
  1064. }
  1065.  
  1066.  
  1067.  
  1068. /* ---
  1069.  
  1070.     Return a list of the current history list
  1071.  
  1072.     DO NOT FREE the returned values
  1073.  
  1074. --- */
  1075. PUBLIC XP_List *
  1076. SHIST_GetList(MWContext * ctxt)
  1077. {
  1078.  
  1079.     /* error checking */
  1080.     if(!ctxt)
  1081.         return NULL;
  1082.  
  1083.     return(ctxt->hist.list_ptr);
  1084.  
  1085. } /* SHIST_GetList */
  1086.  
  1087.  
  1088. /* Returns TRUE if the current page handles Page Services
  1089.    and FALSE if it doesn't.
  1090. */
  1091.  
  1092. PUBLIC int
  1093. SHIST_CurrentHandlesPageServices(MWContext * ctxt)
  1094. {
  1095.     History_entry * entry;
  1096.  
  1097.     if(ctxt){
  1098.         entry = SHIST_GetCurrent(&ctxt->hist);
  1099.         if(entry){
  1100.             return (entry->page_services_url ? TRUE : FALSE);
  1101.         }
  1102.     }
  1103.  
  1104.     return FALSE;
  1105.  
  1106.     
  1107.  
  1108. }
  1109.  
  1110. /* Returns the url of the page that contains the properties
  1111.    of the current page if Page Services is available.  It returns
  1112.    NULL if Page Services is not available*/
  1113. PUBLIC char *
  1114. SHIST_GetCurrentPageServicesURL(MWContext * ctxt)
  1115. {
  1116.     History_entry * entry;
  1117.  
  1118.     if(ctxt){
  1119.         entry = SHIST_GetCurrent(&ctxt->hist);
  1120.         if(entry){
  1121.             return entry->page_services_url;
  1122.         }
  1123.     }
  1124.  
  1125.     return NULL;
  1126.  
  1127. }
  1128.  
  1129.