/* -*- Mode: C++; tab-width: 8; 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.
 */
/* 
   commands.c --- menus and toolbar.
   Created: Jamie Zawinski <jwz@netscape.com>, 27-Jun-94.
 */


#include "mozilla.h"
#include "xfe.h"
#include "felocale.h"
#include "xlate.h"
#include "menu.h"
#include "net.h"
#include "e_kit.h"
#include "prefapi.h"
#include "intl_csi.h"
#include <netdb.h>
#ifdef FORTEZZA
#include "ssl.h"
#endif
#include "selection.h"

#include "outline.h"
#include "layers.h"


#ifdef EDITOR
#include "xeditor.h"
#include "edt.h" /* just for EDT_MailDocument() */
#endif /*EDITOR*/

#ifdef MOZ_MAIL_NEWS
#include "msgcom.h"
#include "msg_srch.h"
#include "mailnews.h"
#endif /* MOZ_MAIL_NEWS */

#include "il_icons.h"           /* Image icon enumeration. */

#include "mozjava.h"

#ifdef X_PLUGINS
#include "np.h"
#endif /* X_PLUGINS */

#ifndef NO_WEB_FONTS
#include "nf.h"
#endif /* NO_WEB_FONTS */

#include <Xm/RowColumn.h>
#include <XmL/Grid.h>

/* for XP_GetString() */
#include <xpgetstr.h>

extern int XFE_COMMANDS_UPLOAD_FILE;
extern int XFE_CANNOT_SEE_FILE;
extern int XFE_CANNOT_READ_FILE;
extern int XFE_IS_A_DIRECTORY;
extern int XFE_UNKNOWN_ESCAPE_CODE;
extern int XFE_LOG_IN_AS;
extern int XFE_COULDNT_FORK;
extern int XFE_EXECVP_FAILED;
extern int XFE_OUT_OF_MEMORY_URL;
extern int XFE_COMMANDS_OPEN_URL_USAGE;
extern int XFE_COMMANDS_HTML_HELP_USAGE;
extern int XFE_COMMANDS_UNPARSABLE_ENCODING_FILTER_SPEC;
extern int XFE_NETSCAPE_MAIL;
extern int XFE_NETSCAPE_NEWS;
extern int XFE_BOOKMARKS;
extern int XFE_ADDRESS_BOOK;
extern int XFE_DOWNLOAD_FILE;
extern int XFE_COMPOSE_NO_SUBJECT;
extern int XFE_COMPOSE;
extern int XFE_NETSCAPE_UNTITLED;
extern int XFE_NETSCAPE;
extern int XFE_COMMANDS_MAIL_TO_USAGE;

extern char* help_menu_names[];
extern char* directory_menu_names[];

extern MWContext * fe_reuseBrowser(MWContext *context,URL_Struct *url);

/* Local forward declarations */
extern void fe_InsertMessageCompositionText(MWContext *context, 
			const char *text,
			XP_Bool leaveCursorAtBeginning);

extern void fe_mailfilter_cb(Widget, XtPointer, XtPointer);

/* Externs from dialog.c: */
extern int fe_await_synchronous_url (MWContext *context);

/* Externs from mozilla.c */
extern char * fe_MakeSashGeometry(char *old_geom_str, int pane_config,
			unsigned int w, unsigned int h);

static void
fe_page_forward_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  Widget sb = CONTEXT_DATA (context)->vscroll;
  XmScrollBarCallbackStruct cb;
  int pi = 0, v = 0, max = 1, min = 0;

  XP_ASSERT(sb);
  if (!sb) return;
  XtVaGetValues (sb, XmNpageIncrement, &pi, XmNvalue, &v,
		 XmNmaximum, &max, XmNminimum, &min, 0);
  cb.reason = XmCR_PAGE_INCREMENT;
  cb.event = 0;
  cb.pixel = 0;
  cb.value = v + pi;
  if (cb.value > max - pi) cb.value = max - pi;
  if (cb.value < min) cb.value = min;
  XtCallCallbacks (sb, XmNvalueChangedCallback, &cb);
}


static void
fe_page_backward_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  Widget sb = CONTEXT_DATA (context)->vscroll;
  XmScrollBarCallbackStruct cb;
  int pi = 0, v = 0, min = 0;

  XP_ASSERT(sb);
  if (!sb) return;
  fe_UserActivity (context);
  XtVaGetValues (sb, XmNpageIncrement, &pi, XmNvalue, &v, XmNminimum, &min, 0);
  cb.reason = XmCR_PAGE_INCREMENT;
  cb.event = 0;
  cb.pixel = 0;
  cb.value = v - pi;
  if (cb.value < min) cb.value = min;
  XtCallCallbacks (sb, XmNvalueChangedCallback, &cb);
}


static void
fe_line_forward_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  Widget sb = CONTEXT_DATA (context)->vscroll;
  XmScrollBarCallbackStruct cb;
  int li = 0, v = 0, max = 1, min = 0;

#ifdef EDITOR
  if (context->is_editor) return;
#endif /* EDITOR */
    
  XP_ASSERT(sb);
  if (!sb) return;
  fe_UserActivity (context);
  XtVaGetValues (sb, XmNincrement, &li, XmNvalue, &v,
		 XmNmaximum, &max, XmNminimum, &min, 0);
  cb.reason = XmCR_INCREMENT;
  cb.event = 0;
  cb.pixel = 0;
  cb.value = v + li;
  if (cb.value > max - li) cb.value = max - li;
  if (cb.value < min) cb.value = min;
  XtCallCallbacks (sb, XmNvalueChangedCallback, &cb);
}


static void
fe_line_backward_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  Widget sb = CONTEXT_DATA (context)->vscroll;
  XmScrollBarCallbackStruct cb;
  int li = 0, v = 0, min = 0;

#ifdef EDITOR
  if (context->is_editor) return;
#endif /* EDITOR */
    
  XP_ASSERT(sb);
  if (!sb) return;
  fe_UserActivity (context);
  XtVaGetValues (sb, XmNincrement, &li, XmNvalue, &v, XmNminimum, &min, 0);
  cb.reason = XmCR_INCREMENT;
  cb.event = 0;
  cb.pixel = 0;
  cb.value = v - li;
  if (cb.value < min) cb.value = min;
  XtCallCallbacks (sb, XmNvalueChangedCallback, &cb);
}

static void
fe_column_forward_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  Widget sb = CONTEXT_DATA (context)->hscroll;
  XmScrollBarCallbackStruct cb;
  int li = 0, v = 0, min = 0;

  XP_ASSERT(sb);
  if (!sb) return;
  fe_UserActivity (context);
  XtVaGetValues (sb, XmNincrement, &li, XmNvalue, &v, XmNminimum, &min, 0);
  cb.reason = XmCR_INCREMENT;
  cb.event = 0;
  cb.pixel = 0;
  cb.value = v - li;
  if (cb.value < min) cb.value = min;
  XtCallCallbacks (sb, XmNvalueChangedCallback, &cb);
}


static void
fe_column_backward_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  Widget sb = CONTEXT_DATA (context)->hscroll;
  XmScrollBarCallbackStruct cb;
  int li = 0, v = 0, max = 1, min = 0;

  XP_ASSERT(sb);
  if (!sb) return;
  fe_UserActivity (context);
  XtVaGetValues (sb, XmNincrement, &li, XmNvalue, &v,
		 XmNmaximum, &max, XmNminimum, &min, 0);
  cb.reason = XmCR_INCREMENT;
  cb.event = 0;
  cb.pixel = 0;
  cb.value = v + li;
  if (cb.value > max - li) cb.value = max - li;
  if (cb.value < min) cb.value = min;
  XtCallCallbacks (sb, XmNvalueChangedCallback, &cb);
}


/* File menu
 */

static void
fe_open_url_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  fe_UserActivity (context);
  fe_OpenURLDialog(context);
}

void
fe_upload_file_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  XmString xm_title;
  char *title = XP_GetString(XFE_COMMANDS_UPLOAD_FILE);
  char *file, *msg;

  fe_UserActivity (context);

  file = fe_ReadFileName (context, title, 0, True, 0);

  /* validate filename */
  if (file) {
    if (!fe_isFileExist(file)) {
      msg = PR_smprintf( XP_GetString( XFE_CANNOT_SEE_FILE ), file);
      if (msg) {
	XFE_Alert(context, msg);
	XP_FREE(msg);
      }
      XP_FREE (file);
      file = NULL;
    }
    else if (!fe_isFileReadable(file)) {
      msg = PR_smprintf( XP_GetString( XFE_CANNOT_READ_FILE ) , file);
      if (msg) {
	XFE_Alert(context, msg);
	XP_FREE(msg);
      }
      XP_FREE (file);
      file = NULL;
    }
    else if (fe_isDir(file)) {
      msg = PR_smprintf( XP_GetString( XFE_IS_A_DIRECTORY ), file);
      if (msg) {
	  XFE_Alert(context, msg);
	  if (msg) XP_FREE(msg);
      }
      XP_FREE (file);
      file = NULL;
    }
  }

  if (file)
    {
      History_entry *he = SHIST_GetCurrent (&context->hist);
      URL_Struct *url;

      if (he && he->address && (XP_STRNCMP (he->address, "ftp://", 6) == 0)
	  && he->address [strlen (he->address)-1] == '/')
	{
	  url = NET_CreateURLStruct (he->address, NET_SUPER_RELOAD);
	  if (!url)
	    {
	      XP_FREE (file);
	      return;
	    }
	  url->method = URL_POST_METHOD;
	  url->files_to_post = XP_ALLOC (2);
	  if (!url->files_to_post)
	    {
	      XP_FREE (file);
	      return;
	    }

	  url->files_to_post [0] = XP_STRDUP ((const char *) file);
	  url->files_to_post [1] = 0;

	  fe_GetURL (context, url, FALSE);
	}

      XP_FREE (file);
    }
}

void
fe_reload_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  XmPushButtonCallbackStruct *cd = (XmPushButtonCallbackStruct *) call_data;
  
  fe_UserActivity (context);
  
  if (cd && cd->event->xkey.state & ShiftMask)
    fe_ReLayout (context, NET_SUPER_RELOAD);
  else
    fe_ReLayout (context, NET_NORMAL_RELOAD);
}

/* not static -- it's needed by src/HTMLView.cpp */
void
fe_abort_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  fe_UserActivity (context);
  fe_AbortCallback (widget, closure, call_data);
}

void
fe_refresh_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  Widget wid;
  Display *dpy;
  Window win;
  Dimension w = 0, h = 0;
  XGCValues gcv;
  GC gc;

  if (fe_IsGridParent (context)) context = fe_GetFocusGridOfContext (context);
  XP_ASSERT (context);
  if (!context) return;

  wid = CONTEXT_DATA (context)->drawing_area;
  if (wid == NULL) return;

  dpy = XtDisplay (wid);
  win = XtWindow (wid);

  fe_UserActivity (context);

  XtVaGetValues (wid, XmNbackground, &gcv.foreground,
		 XmNwidth, &w, XmNheight, &h, 0);
  gc = XCreateGC (dpy, win, GCForeground, &gcv);
  XFillRectangle (dpy, win, gc, 0, 0, w, h);
  XFreeGC (dpy, gc);

  if (context->compositor) {
    XP_Rect rect;
    
    rect.left = CONTEXT_DATA(context)->document_x;
    rect.top = CONTEXT_DATA(context)->document_y;
    rect.right = rect.left + w;
    rect.bottom = rect.top + h;
    CL_UpdateDocumentRect(context->compositor,
			  &rect, (PRBool)FALSE);
  }
}


char **fe_encoding_extensions = 0; /* gag.  used by mkcache.c. */



#ifdef EDITOR
/*
 *    Hack, hack, hack. These are in editor.c, please move the menu
 *    definition there.
 */
extern void fe_editor_view_source_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_edit_source_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_browse_doc_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_about_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_open_file_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_edit_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_paragraph_style_menu_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_paragraph_style_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_new_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_new_from_wizard_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_new_from_template_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_open_file_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_save_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_save_as_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_edit_menu_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_undo_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_redo_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_view_menu_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_properties_menu_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_hrule_properties_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_display_tables_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_paragraph_marks_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_insert_menu_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_insert_link_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_insert_target_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_insert_image_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_insert_hrule_dialog_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_insert_html_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_insert_line_break_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_insert_non_breaking_space_cb(Widget,XtPointer,XtPointer);
extern void fe_editor_char_props_menu_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_toggle_char_props_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_char_props_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_clear_char_props_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_font_size_menu_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_font_size_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_paragraph_props_menu_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_paragraph_props_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_indent_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_properties_dialog_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_delete_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_refresh_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_insert_hrule_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_cut_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_copy_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_paste_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_table_menu_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_table_insert_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_table_row_insert_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_table_column_insert_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_table_cell_insert_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_table_delete_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_table_row_delete_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_table_column_delete_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_table_cell_delete_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_file_menu_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_document_properties_dialog_cb(Widget, XtPointer,
						    XtPointer);
extern void fe_editor_preferences_dialog_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_target_properties_dialog_cb(Widget, XtPointer,
						    XtPointer);
extern void fe_editor_html_properties_dialog_cb(Widget, XtPointer,
						XtPointer);
extern void fe_editor_table_properties_dialog_cb(Widget, XtPointer,
						 XtPointer);
extern void fe_editor_publish_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_find_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_find_again_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_windows_menu_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_select_all_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_delete_item_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_select_table_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_reload_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_set_colors_dialog_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_default_color_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_remove_links_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_open_url_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_options_menu_cb(Widget, XtPointer, XtPointer);
extern void fe_editor_browse_publish_location_cb(Widget, XtPointer, XtPointer);

#endif /* EDITOR */

/* not static -- it's needed by src/HTMLView.cpp */
void
fe_save_as_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  URL_Struct *url;

  fe_UserActivity (context);

  {
    MWContext *ctx = fe_GetFocusGridOfContext (context);
    if (ctx)
      context = ctx;
  }

  url =	SHIST_CreateWysiwygURLStruct (context,
					    SHIST_GetCurrent (&context->hist));

  if (url)
    fe_SaveURL (context, url);
  else
    FE_Alert (context, fe_globalData.no_url_loaded_message);
}

/* not static -- it's needed by src/HTMLView.cpp */
void
fe_save_top_frame_as_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  URL_Struct *url;

  fe_UserActivity (context);

  url =	SHIST_CreateWysiwygURLStruct (context,
					    SHIST_GetCurrent (&context->hist));

  if (url)
    fe_SaveURL (context, url);
  else
    FE_Alert (context, fe_globalData.no_url_loaded_message);
}

static unsigned int
fe_save_as_stream_write_ready_method (NET_StreamClass *stream)
{
  return(MAX_WRITE_READY);
}

struct view_source_data
{
  MWContext *context;
  Widget widget;
};


void
fe_view_source_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  History_entry *h;
  URL_Struct *url;
  char *new_url_add=0;

  h = SHIST_GetCurrent (&context->hist);
  url = SHIST_CreateURLStructFromHistoryEntry(context, h);
  if (! url)
    {
      FE_Alert (context, fe_globalData.no_url_loaded_message);
      return;
    }

  /* check to make sure it doesn't already have a view-source
   * prefix.  If it does then this window is already viewing
   * the source of another window.  In this case just
   * show the same thing by reloading the url...
   */
  if(strncmp(VIEW_SOURCE_URL_PREFIX, 
			 url->address, 
			 sizeof(VIEW_SOURCE_URL_PREFIX)-1))
    {
      /* prepend VIEW_SOURCE_URL_PREFIX to the url to
       * get the netlib to display the source view
       */
      StrAllocCopy(new_url_add, VIEW_SOURCE_URL_PREFIX);
      StrAllocCat(new_url_add, url->address);
      free(url->address);
      url->address = new_url_add;
    }

   /* make damn sure the form_data slot is zero'd or else all
    * hell will break loose
    */
   XP_MEMSET (&url->savedData, 0, sizeof (SHIST_SavedData));

#ifdef EDITOR
   if (EDT_IS_EDITOR(context) && !FE_CheckAndSaveDocument(context))
	   return;
#endif

/*
  fe_GetSecondaryURL (context, url, FO_PRESENT, NULL, FALSE);
*/
  fe_GetURL (context, url, FALSE);

}

static int
fe_view_source_stream_write_method (NET_StreamClass *stream, const char *str, int32 len)
{
  struct view_source_data *vsd = (struct view_source_data *) stream->data_object;
  char buf [1024];
  XmTextPosition pos, cpos;

  if (!vsd || !vsd->widget) return -1;
  pos = XmTextGetLastPosition (vsd->widget);
  cpos = 0;
  XtVaGetValues (vsd->widget, XmNcursorPosition, &cpos, 0);

  /* We copy the data first because XmTextInsert() needs a null-terminated
     string, and there isn't necessarily room on the end of `str' for us
     to plop down a null. */
  while (len > 0)
    {
      int i;
      int L = (len > (sizeof(buf)-1) ? (sizeof(buf)-1) : len);
      memcpy (buf, str, L);
      buf [L] = 0;
      str += L;
      len -= L;
      /* Crockishly translate CR to LF for the Motif text widget... */
      for (i = 0; i < L; i++)
	if (buf[i] == '\r' && buf[i+1] != '\n')
	  buf[i] = '\n';
      XmTextInsert (vsd->widget, pos, buf);
      pos += L;
    }
  XtVaSetValues (vsd->widget, XmNcursorPosition, cpos, 0);
  return 1;
}

static void
fe_view_source_stream_complete_method (NET_StreamClass *stream)
{
  struct view_source_data *vsd = (struct view_source_data *) stream->data_object;
  free (vsd);
}

static void
fe_view_source_stream_abort_method (NET_StreamClass *stream, int status)
{
  struct view_source_data *vsd = (struct view_source_data *) stream->data_object;
  free (vsd);
}


/* Creates and returns a stream object which writes the data read into a
   text widget.
 */
NET_StreamClass *
fe_MakeViewSourceStream (int format_out, void *data_obj,
			 URL_Struct *url_struct, MWContext *context)
{
  struct view_source_data *vsd;
  NET_StreamClass* stream;

  if (url_struct->is_binary)
    {
      FE_Alert (context, fe_globalData.binary_document_message);
      return 0;
    }

  vsd = url_struct->fe_data;
  if (! vsd) abort ();
  url_struct->fe_data = 0;

  stream = (NET_StreamClass *) calloc (sizeof (NET_StreamClass), 1);
  if (!stream) return 0;

  stream->name           = "ViewSource";
  stream->complete       = fe_view_source_stream_complete_method;
  stream->abort          = fe_view_source_stream_abort_method;
  stream->put_block      = fe_view_source_stream_write_method;
  stream->is_write_ready = fe_save_as_stream_write_ready_method;
  stream->data_object    = vsd;
  stream->window_id      = context;
  return stream;
}

#if defined(MOZ_MAIL_NEWS) || defined(MOZ_MAIL_COMPOSE)

/* Mailing documents
 */

void
fe_mailNew_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  fe_UserActivity (context);
  MSG_Mail (context);
}


void
fe_mailto_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  fe_UserActivity (context);

  /*
   * You cannot mail a frameset, you must mail the frame child
   * with focus
   */
  if (fe_IsGridParent (context))
    {
      MWContext *ctx = fe_GetFocusGridOfContext (context);
      if (ctx)
        context = ctx;
    }
#ifdef EDITOR
  if (EDT_IS_EDITOR(context))
	  EDT_MailDocument (context);
  else
#endif
	  MSG_MailDocument (context);

}

#endif  /* MOZ_MAIL_NEWS || MOZ_MAIL_COMPOSE */

void
fe_print_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  URL_Struct *url;

  fe_UserActivity (context);

#ifdef EDITOR
  if (EDT_IS_EDITOR(context) && !FE_CheckAndSaveDocument(context))
      return;
#endif

  {
    MWContext *ctx = fe_GetFocusGridOfContext (context);
    if (ctx)
      context = ctx;
  }

  url = SHIST_CreateURLStructFromHistoryEntry (context, SHIST_GetCurrent(&context->hist));
  if (url) {
    /* Free the url struct we created */
    NET_FreeURLStruct(url);

#ifdef X_PLUGINS
    if (CONTEXT_DATA(context)->is_fullpage_plugin) {
      /* Full page plugins need a step here. We need to ask the plugin if
       * it wants to handle the printing.
       */
      NPPrint npprint;
      
      npprint.mode = NP_FULL;
      npprint.print.fullPrint.pluginPrinted = FALSE;
      npprint.print.fullPrint.printOne = TRUE;
      npprint.print.fullPrint.platformPrint = NULL;
      NPL_Print(context->pluginList, &npprint);
      if (npprint.print.fullPrint.pluginPrinted == TRUE)
	return;
    }
#endif /* X_PLUGINS */

    fe_PrintDialog (context);
  }
  else
    FE_Alert(context, fe_globalData.no_url_loaded_message);
}

#define fe_quit_cb fe_QuitCallback
void
fe_QuitCallback (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;

  fe_UserActivity (context);
#ifdef MOZ_MAIL_NEWS
  if (!fe_CheckUnsentMail ())
    return;
  if (!fe_CheckDeferredMail ())
    return;
#endif
#ifdef EDITOR
  if (!fe_EditorCheckUnsaved(context))
      return;
#endif /*EDITOR*/
  if (!CONTEXT_DATA (context)->confirm_exit_p ||
      FE_Confirm (context, fe_globalData.really_quit_message))
    {
      fe_AbortCallback (widget, closure, call_data);
      fe_Exit (0);
    }
}


/* FIND */

void
fe_find_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  MWContext *top_context;

  fe_unset_findcommand_context();

  top_context = XP_GetNonGridContext(context);
  if (!top_context) top_context = context;

  fe_UserActivity (top_context);

  fe_FindDialog (top_context, False);
}


void
fe_find_again_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  MWContext *top_context;
  fe_FindData *find_data;

  fe_unset_findcommand_context();

  top_context = XP_GetNonGridContext(context);
  if (!top_context) top_context = context;

  fe_UserActivity (top_context);

  find_data = CONTEXT_DATA(top_context)->find_data;

  if ((top_context->type == MWContextBrowser
#ifdef MOZ_MAIL_NEWS
	|| top_context->type == MWContextMail
	|| top_context->type == MWContextNews
	|| top_context->type == MWContextMailMsg
#endif
	) &&
      find_data && find_data->string && find_data->string[0] != '\0')
    fe_FindDialog (top_context, True);
  else
    XBell (XtDisplay (widget), 0);
}


#ifdef FORTEZZA

static void
fe_fortezza_card_cb (Widget widget,
		       XtPointer closure,
		       XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  fe_UserActivity (context);

  SSL_FortezzaMenu(context,SSL_FORTEZZA_CARD_SELECT);
}

static void
fe_fortezza_change_cb (Widget widget,
		       XtPointer closure,
		       XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  fe_UserActivity (context);
  SSL_FortezzaMenu(context,SSL_FORTEZZA_CHANGE_PERSONALITY);
}

static void
fe_fortezza_view_cb (Widget widget,
		       XtPointer closure,
		       XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  fe_UserActivity (context);
  SSL_FortezzaMenu(context,SSL_FORTEZZA_VIEW_PERSONALITY);
}

static void
fe_fortezza_info_cb (Widget widget,
		       XtPointer closure,
		       XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  fe_UserActivity (context);
  SSL_FortezzaMenu(context,SSL_FORTEZZA_CARD_INFO);
}

static void
fe_fortezza_logout_cb (Widget widget,
		       XtPointer closure,
		       XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  fe_UserActivity (context);
  SSL_FortezzaMenu(context,SSL_FORTEZZA_LOGOUT);
}
#endif


#define HTTP_OFF		42

	/* "about:document" */
#define DOCINFO			"about:document"

	/* ".netscape.com/" */
#define DOT_NETSCAPE_DOT_COM_SLASH \
				"\130\230\217\236\235\215\213\232\217\130\215"\
				"\231\227\131"

	/* "http://home.netscape.com/" */
#define HTTP_NETSCAPE		"\222\236\236\232\144\131\131\222\231\227\217"\
				"\130\230\217\236\235\215\213\232\217\130\215"\
				"\231\227\131"

	/* "http://cgi.netscape.com/cgi-bin/" */
#define HTTP_CGI		"\222\236\236\232\144\131\131\215\221\223\130"\
				"\230\217\236\235\215\213\232\217\130\215\231"\
				"\227\131\215\221\223\127\214\223\230\131"

        /* "http://home.netscape.com/home/" */
#define HTTP_HOME               "\222\236\236\232\144\131\131\222\231\227\217"\
                                "\130\230\217\236\235\215\213\232\217\130\215"\
                                "\231\227\131\222\231\227\217\131"

        /* "http://home.netscape.com/eng/mozilla/4.0/" */
#define HTTP_ENG                "\222\236\236\232\144\131\131\222\231\227\217"\
                                "\130\230\217\236\235\215\213\232\217\130\215"\
                                "\231\227\131\217\230\221\131\227\231\244\223"\
                		"\226\226\213\131\136\130\132\131"

        /* "http://home.netscape.com/eng/mozilla/2.0/" */
#define HTTP_ENG_2_0            "\222\236\236\232\144\131\131\222\231\227\217"\
                                "\130\230\217\236\235\215\213\232\217\130\215"\
                                "\231\227\131\217\230\221\131\227\231\244\223"\
                                "\226\226\213\131\134\130\132\131"

		/* "http://guide.netscape.com/" */
#define HTTP_GUIDE              "\222\236\236\232\144\131\131\221\237\223"\
                                "\216\217\130\230\217\236\235\215\213\232"\
                                "\217\130\215\231\227\131"

        /* "http://help.netscape.com/" */
#define HTTP_HELP         "\222\236\236\232\144\131\131\222\217\226\232"\
                          "\130\230\217\236\235\215\213\232\217\130\215"\
                          "\231\227\131"

        /* "http://home.netscape.com/info/" */
#define HTTP_INFO               "\222\236\236\232\144\131\131\222\231\227\217"\
                                "\130\230\217\236\235\215\213\232\217\130\215"\
                                "\231\227\131\223\230\220\231\131"

        /* "fishcam/" */
#define HTTP_FC                 HTTP_NETSCAPE \
                                "\220\223\235\222\215\213\227\131"

#ifdef MOZ_MAIL_NEWS
        /* "newsrc:" */
#define HTTP_NEWSRC             "\230\217\241\235\234\215\144"
#endif
 
        /* "whats_new/" */
#define HTTP_WHATS_NEW          HTTP_GUIDE \
                                "\241\222\213\236\235\211\230\217\241\131"
        /* "whats_cool/" */
#define HTTP_WHATS_COOL         HTTP_GUIDE \
                                "\241\222\213\236\235\211\215\231\231\226"\
                                "\131"
        /* "" */
#define HTTP_INET_DIRECTORY     HTTP_GUIDE
 
        /* "internet-search.html" */
#define HTTP_INET_SEARCH        HTTP_HOME "\223\230\236\217\234\230\217\236"\
                                "\127\235\217\213\234\215\222\130\222\236\227"\
                                "\226"
        /* "people/" */
#define HTTP_INET_WHITE         HTTP_GUIDE \
                                "\232\217\231\232\226\217\131"
 
        /* "yellow_pages/" */
#define HTTP_INET_YELLOW        HTTP_GUIDE \
                                "\243\217\226\226\231\241\211\232\213\221"\
                                "\217\235\131"

        /* "about-the-internet.html" */
#define HTTP_INET_ABOUT         HTTP_HOME "\213\214\231\237\236\127\236\222"\
                                "\217\127\223\230\236\217\234\230\217\236\130"\
                                "\222\236\227\226"
 
        /* "update.html" */
#define HTTP_SOFTWARE           HTTP_HOME "\237\232\216\213\236\217\130\222\236\227\226"
 
        /* "how-to-create-web-services.html" */
#define HTTP_HOWTO              HTTP_HOME "\222\231\241\127\236\231\127\215"\
                                "\234\217\213\236\217\127\241\217\214\127\235"\
                                "\217\234\240\223\215\217\235\130\222\236\227"\
                                "\226"
        /* "netscape-galleria.html" */
#define HTTP_GALLERIA           HTTP_HOME "\230\217\236\235\215\213\232\217"\
                                "\127\221\213\226\226\217\234\223\213\130\222"\
                                "\236\227\226"
 
        /* "relnotes/unix-" */
# define HTTP_REL_VERSION_PREFIX HTTP_ENG "\234\217\226\230\231\236\217\235"\
                                "\131\237\230\223\242\127"
 
# define HTTP_BETA_VERSION_PREFIX H_REL_VERSION_PREFIX
 
        /* "reginfo-x.cgi" */
#define HTTP_REG		HTTP_HOME "\234\217\221\223\235\236\217\234\130\222\236\227\226"

 
        /* "handbook/" */
#define HTTP_MANUAL             HTTP_ENG "\222\213\230\216\214\231\231\225\131"

	/* "starter.html" */
#define HTTP_STARTER            HTTP_HOME "\235\236\213\234\236\217\234\130"\
				"\222\236\227\226"

#ifdef NON_BETA
       /* "http://help.netscape.com/faqs.html" */
#define HTTP_FAQ                "\222\236\236\232\144\131\131\222\217\226\232"\
                                "\130\230\217\236\235\215\213\232\217\130\215"\
                                "\231\227\131\220\213\233\235\130\222\236\227"\
                                "\226" 
#else
        /* "eng/beta_central/faq/index.html" */
#define HTTP_FAQ		HTTP_NETSCAPE "\217\230\221\131\214\217\236"\
				"\213\211\215\217\230\236\234\213\226\131\220\213\233"\
				"\131\223\230\216\217\242\130\222\236\227\226"
#endif
 
        /* "security-doc.html" */
#define HTTP_SECURITY           HTTP_INFO "\235\217\215\237\234\223\236\243"\
                                "\127\216\231\215\130\222\236\227\226"
 
#ifdef NON_BETA
        /* "auto_bug.cgi" */
#define HTTP_FEEDBACK		HTTP_CGI "\213\237\236\231\211\214\237\221"\
				"\130\215\221\223"
#else
        /* "eng/beta_central" */
#define HTTP_FEEDBACK		HTTP_NETSCAPE "\217\230\221\131\214\217\236"\
				"\213\211\215\217\230\236\234\213\226"
#endif
 
#ifdef NON_BETA
        /* "http://help.netscape.com/" */
#define HTTP_SUPPORT            "\222\236\236\232\144\131\131\222\217\226\232"\
				"\130\230\217\236\235\215\213\232\217\130\215"\
				"\231\227\131"
#else
        /* "eng/beta_central" */
#define HTTP_SUPPORT		HTTP_NETSCAPE "\217\230\221\131\214\217\236"\
				"\213\211\215\217\230\236\234\213\226"
#endif

#ifdef MOZ_MAIL_NEWS
        /* "news/news.html" */
#define HTTP_USENET         HTTP_ENG_2_0 "\230\217\241\235\131\230\217\241"\
                                "\235\130\222\236\227\226"
#endif

        /* "about:plugins" */
#define HTTP_PLUGINS "\213\214\231\237\236\144\232\226\237\221\223\230\235"

        /* "about:fonts" */
#define HTTP_FONTS "\213\214\231\237\236\144\220\231\230\236\235"

#ifdef __sgi

	/* "http://www.sgi.com/surfer/silicon_sites.html" */
# define HTTP_SGI_MENU "\222\236\236\232\144\131\131\241\241\241\130\235\221"\
		  "\223\130\215\231\227\131\235\237\234\220\217\234\131\235"\
		  "\223\226\223\215\231\230\211\235\223\236\217\235\130\222"\
		  "\236\227\226"

	/* "http://www.sgi.com" */
# define HTTP_SGI_BUTTON "\222\236\236\232\144\131\131\241\241\241\130\235"\
			 "\221\223\130\215\231\227"

	/* "file:/usr/local/lib/netscape/docs/Welcome.html" */
# define HTTP_SGI_WELCOME "\220\223\226\217\144\131\237\235\234\131\226\231"\
			  "\215\213\226\131\226\223\214\131\230\217\236\235"\
			  "\215\213\232\217\131\216\231\215\235\131\201\217"\
			  "\226\215\231\227\217\130\222\236\227\226"

	/* "http://www.adobe.com" */
# define HTTP_ADOBE_MENU "\222\236\236\232\144\131\131\241\241\241\130\213"\
			 "\216\231\214\217\130\215\231\227"

	/* "http://www.sgi.com/surfer/cool_sites.html" */
# define SGI_WHATS_COOL  "\222\236\236\232\144\131\131\241\241\241\130\235"\
			 "\221\223\130\215\231\227\131\235\237\234\220\217"\
			 "\234\131\215\231\231\226\211\235\223\236\217\235"\
			 "\130\222\236\227\226"

	/* "http://www.sgi.com/surfer/netscape/relnotes-" */
# define SGI_VERSION_PREFIX	"\222\236\236\232\144\131\131\241\241\241\130"\
				"\235\221\223\130\215\231\227\131\235\237\234"\
				"\220\217\234\131\230\217\236\235\215\213\232"\
				"\217\131\234\217\226\230\231\236\217\235\127"

#endif /* __sgi */

	/* "products/client/communicator/" */
#define HTTP_PRODUCT_INFO HTTP_HELP "\232\234\231\216\237\215\236"\
				"\235\131\215\226\223\217\230\236\131\215\231\227"\
				"\227\237\230\223\215\213\236\231\234\131"

	/* "http://home.netscape.com/eng/intl/" */
#define HTTP_INTL "\222\236\236\232\144\131\131\222\231\227\217\130"\
				"\230\217\236\235\215\213\232\217\130\215\231\227"\
				"\131\217\230\221\131\223\230\236\226\131"

	/* "services.html" */
#define HTTP_SERVICES HTTP_HOME "\235\217\234\240\223\215\217\235"\
				"\130\222\236\227\226"


static char *
go_get_url(char *which)
{
	char		clas[128];
	char		name[128];
	char		*p;
	char		*ret;
	char		*type;
	XrmValue	value;

	PR_snprintf(clas, sizeof (clas), "%s.Url.Which", fe_progclass);
	PR_snprintf(name, sizeof (name), "%s.url.%s", fe_progclass, which);
	if (XrmGetResource(XtDatabase(fe_display), name, clas, &type, &value))
	{
		ret = strdup(value.addr);
		if (!ret)
		{
			return NULL;
		}
		p = ret;
		while (*p)
		{
			*p += HTTP_OFF;
			p++;
		}
		if (!strstr(ret, DOT_NETSCAPE_DOT_COM_SLASH))
		{
			free(ret);
			return NULL;
		}
		return ret;
	}

	return NULL;
}


#define GO_GET_URL(func, res)			\
	static char *				\
	func(char *builtin)			\
	{					\
		static char	*ret = NULL;	\
						\
		if (ret)			\
		{				\
			return ret;		\
		}				\
						\
		ret = go_get_url(res);		\
		if (ret)			\
		{				\
			return ret;		\
		}				\
						\
		return builtin;			\
	}


GO_GET_URL(go_get_url_plugins, "aboutplugins")
GO_GET_URL(go_get_url_fonts, "aboutfonts")
GO_GET_URL(go_get_url_whats_new, "whats_new")
GO_GET_URL(go_get_url_whats_cool, "whats_cool")
GO_GET_URL(go_get_url_inet_directory, "directory")
GO_GET_URL(go_get_url_inet_search, "search")
GO_GET_URL(go_get_url_inet_white, "white")
GO_GET_URL(go_get_url_inet_yellow, "yellow")
GO_GET_URL(go_get_url_inet_about, "about")
GO_GET_URL(go_get_url_software, "software")
GO_GET_URL(go_get_url_howto, "howto")
GO_GET_URL(go_get_url_netscape, "netscape")
GO_GET_URL(go_get_url_galleria, "galleria")
GO_GET_URL(go_get_url_starter, "starter")
GO_GET_URL(go_get_url_rel_version_prefix, "rel_notes")
GO_GET_URL(go_get_url_reg, "reg")
GO_GET_URL(go_get_url_manual, "manual")
GO_GET_URL(go_get_url_faq, "faq")
GO_GET_URL(go_get_url_usenet, "usenet")
GO_GET_URL(go_get_url_security, "security")
GO_GET_URL(go_get_url_feedback, "feedback")
GO_GET_URL(go_get_url_support, "support")
GO_GET_URL(go_get_url_product_info, "productInfo")
GO_GET_URL(go_get_url_intl, "intl")
GO_GET_URL(go_get_url_services, "services")


#define H_WHATS_NEW             go_get_url_whats_new(HTTP_WHATS_NEW)
#define H_WHATS_COOL            go_get_url_whats_cool(HTTP_WHATS_COOL)
#define H_INET_DIRECTORY        go_get_url_inet_directory(HTTP_INET_DIRECTORY)
#define H_INET_SEARCH           go_get_url_inet_search(HTTP_INET_SEARCH)
#define H_INET_WHITE            go_get_url_inet_white(HTTP_INET_WHITE)
#define H_INET_YELLOW           go_get_url_inet_yellow(HTTP_INET_YELLOW)
#define H_INET_ABOUT            go_get_url_inet_about(HTTP_INET_ABOUT)
#define H_SOFTWARE              go_get_url_software(HTTP_SOFTWARE)
#define H_HOWTO                 go_get_url_howto(HTTP_HOWTO)
#define H_NETSCAPE              go_get_url_netscape(HTTP_NETSCAPE)
#define H_GALLERIA              go_get_url_galleria(HTTP_GALLERIA)
#define H_REL_VERSION_PREFIX    go_get_url_rel_version_prefix(HTTP_REL_VERSION_PREFIX)
#define H_REG                   go_get_url_reg(HTTP_REG)
#define H_MANUAL                go_get_url_manual(HTTP_MANUAL)
#define H_STARTER               go_get_url_starter(HTTP_STARTER)
#define H_FAQ                   go_get_url_faq(HTTP_FAQ)
#define H_USENET                go_get_url_usenet(HTTP_USENET)
#define H_SECURITY              go_get_url_security(HTTP_SECURITY)
#define H_FEEDBACK              go_get_url_feedback(HTTP_FEEDBACK)
#define H_SUPPORT               go_get_url_support(HTTP_SUPPORT)
#define H_PRODUCT_INFO          go_get_url_product_info(HTTP_PRODUCT_INFO)
#define H_INTL                  go_get_url_intl(HTTP_INTL)
#define H_SERVICES              go_get_url_services(HTTP_SERVICES)

/*
 * EXPORT_URL creates a function that returns a localized URL.
 * It is needed by the e-kit in order to allow localized URL's.
 */
#define EXPORT_URL(func, builtin) char* xfe_##func(void) {return func(builtin);}

EXPORT_URL(go_get_url_plugins, HTTP_PLUGINS)
EXPORT_URL(go_get_url_fonts, HTTP_FONTS)
EXPORT_URL(go_get_url_whats_new, HTTP_WHATS_NEW)
EXPORT_URL(go_get_url_whats_cool, HTTP_WHATS_COOL)
EXPORT_URL(go_get_url_inet_directory, HTTP_INET_DIRECTORY)
EXPORT_URL(go_get_url_inet_search, HTTP_INET_SEARCH)
EXPORT_URL(go_get_url_inet_white, HTTP_INET_WHITE)
EXPORT_URL(go_get_url_inet_yellow, HTTP_INET_YELLOW)
EXPORT_URL(go_get_url_inet_about, HTTP_INET_ABOUT)
EXPORT_URL(go_get_url_software, HTTP_SOFTWARE)
EXPORT_URL(go_get_url_howto, HTTP_HOWTO)
EXPORT_URL(go_get_url_netscape, HTTP_NETSCAPE)
EXPORT_URL(go_get_url_galleria, HTTP_GALLERIA)
EXPORT_URL(go_get_url_reg, HTTP_REG)
EXPORT_URL(go_get_url_manual, HTTP_MANUAL)
EXPORT_URL(go_get_url_starter, HTTP_STARTER)
EXPORT_URL(go_get_url_faq, HTTP_FAQ)
#ifdef MOZ_MAIL_NEWS
EXPORT_URL(go_get_url_usenet, HTTP_USENET)
#endif
EXPORT_URL(go_get_url_security, HTTP_SECURITY)
EXPORT_URL(go_get_url_feedback, HTTP_FEEDBACK)
EXPORT_URL(go_get_url_support, HTTP_SUPPORT)
EXPORT_URL(go_get_url_product_info, HTTP_PRODUCT_INFO)
EXPORT_URL(go_get_url_intl, HTTP_INTL)
EXPORT_URL(go_get_url_services, HTTP_SERVICES)

/*
 * xfe_go_get_url_relnotes
 */
char*
xfe_go_get_url_relnotes(void)
{
  static char* url = NULL;

  if ( url == NULL ) {
      char buf[1024];
      char* ptr;
      char* prefix = (strchr(fe_version, 'a') || strchr(fe_version, 'b'))
                     ? HTTP_BETA_VERSION_PREFIX
                     : H_REL_VERSION_PREFIX;

      sprintf(buf, "%s.html", fe_version);

      for ( ptr = buf; *ptr; ptr++ ) {
          *ptr+= HTTP_OFF;
      }
      url = (char*) malloc(strlen(prefix)+strlen(buf)+1);
      strcpy(url, prefix);
      strcat(url, buf);
  }

  return url;
}

void
fe_docinfo_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  char buf [1024], *in, *out;
  fe_UserActivity (context);
  for (in = DOCINFO, out = buf; *in; in++, out++) *out = *in - HTTP_OFF;
    *out = 0;

#ifdef EDITOR
  if (EDT_IS_EDITOR(context) && !FE_CheckAndSaveDocument(context))
    return;
#endif
  /* @@@@ this is the proper way to do it but I dont'
   * know the encoding scheme
   * fe_GetURL (context,NET_CreateURLStruct(buf, FALSE), FALSE);
   */
  fe_GetURL (context,NET_CreateURLStruct(DOCINFO, FALSE), FALSE);

#ifdef EDITOR
  fe_EditorRefresh(context);
#endif
}

char *
xfe_get_netscape_home_page_url()
{
  static char buf [128];
  char *in, *out;
  for (in = H_NETSCAPE, out = buf; *in; in++, out++) *out = *in - HTTP_OFF;
  *out = 0;
  return buf;
}

static void
fe_net_showstatus_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  char *rv;

  fe_UserActivity (context);
  rv = NET_PrintNetlibStatus();
  NET_ToggleTrace();  /* toggle trace mode on and off */
  XFE_Alert (context, rv);
  free(rv);
}

static void
fe_fishcam_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  char buf [1024], *in, *out;
  fe_UserActivity (context);
  for (in = HTTP_FC, out = buf; *in; in++, out++) *out = *in - HTTP_OFF;
  *out = 0;
  fe_GetURL (context,NET_CreateURLStruct(buf, FALSE), FALSE);
}

void
fe_SearchCallback (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  char* url;
  fe_UserActivity (context);
  if ( PREF_GetUrl("internal_url.net_search", &url) ) {
    fe_GetURL (context,NET_CreateURLStruct(url, FALSE), FALSE);
  }
}

void
fe_GuideCallback (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  char* url = NULL;
  int ok;

  fe_UserActivity (context);

  ok = PREF_CopyConfigString("toolbar.places.default_url",&url);

  if (ok == PREF_NOERROR) 
  {
      FE_GetURL(context,NET_CreateURLStruct(url,NET_DONT_RELOAD));
  }                                                                       
  
  if (url)
  {
      XP_FREE(url);  
  }
}

void
fe_NetscapeCallback (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  char* url;
  fe_UserActivity (context);

  if ( PREF_GetUrl("toolbar.logo", &url) ) {
	  /*
	   *    Call this guy, it will sort out if the current context
	   *    is suitable, etc...
	   */
	  FE_GetURL(context,  NET_CreateURLStruct(url, NET_DONT_RELOAD));
  }
}

#ifdef __sgi
static void
fe_sgi_menu_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  char buf [1024], *in, *out;
  fe_UserActivity (context);
  for (in = HTTP_SGI_MENU, out = buf; *in; in++, out++) *out = *in - HTTP_OFF;
  *out = 0;
  fe_GetURL (context, NET_CreateURLStruct (buf, FALSE), FALSE);
}

static void
fe_adobe_menu_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  char buf [1024], *in, *out;
  fe_UserActivity (context);
  for (in = HTTP_ADOBE_MENU, out = buf; *in; in++, out++)
    *out = *in - HTTP_OFF;
  *out = 0;
  fe_GetURL (context, NET_CreateURLStruct (buf, FALSE), FALSE);
}

void
fe_SGICallback (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  char buf [1024], *in, *out;
  fe_UserActivity (context);
  for (in = HTTP_SGI_BUTTON, out = buf; *in; in++, out++)
    *out = *in - HTTP_OFF;
  *out = 0;
  fe_GetURL (context, NET_CreateURLStruct (buf, FALSE), FALSE);
}

void
fe_sgi_welcome_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  char buf [1024], *in, *out;
  fe_UserActivity (context);
  for (in = HTTP_SGI_WELCOME, out = buf; *in; in++, out++)
    *out = *in - HTTP_OFF;
  *out = 0;
  fe_GetURL (context, NET_CreateURLStruct (buf, FALSE), FALSE);
}
#endif /* __sgi */

#ifdef JAVA

void
fe_new_show_java_console_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  LJ_HideConsole();
  LJ_ShowConsole();
}

#endif

void
fe_load_images_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  fe_UserActivity (context);
  fe_LoadDelayedImages (context);
}

/* Navigate menu
 */

/* not static -- it's needed by src/HTMLView.cpp */
void
fe_back_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  MWContext *top_context = XP_GetNonGridContext(context);
  URL_Struct *url;
  if (fe_IsGridParent(top_context))
    {
        if (LO_BackInGrid(top_context))
          {
            return;
          }
    }
  fe_UserActivity (top_context);
  url = SHIST_CreateURLStructFromHistoryEntry (top_context,
					       SHIST_GetPrevious (top_context));
  if (url)
    {
      fe_GetURL (top_context, url, FALSE);
    }
  else
    {
      FE_Alert (top_context, fe_globalData.no_previous_url_message);
    }
}

/* not static -- it's needed by src/HTMLView.cpp */
void
fe_forward_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  MWContext *top_context = XP_GetNonGridContext(context);
  URL_Struct *url;
  if (fe_IsGridParent(top_context))
    {
        if (LO_ForwardInGrid(top_context))
          {
            return;
          }
    }
  fe_UserActivity (top_context);
  url = SHIST_CreateURLStructFromHistoryEntry (top_context,
					       SHIST_GetNext (top_context));
  if (url)
    {
      fe_GetURL (top_context, url, FALSE);
    }
  else
    {
      FE_Alert (top_context, fe_globalData.no_next_url_message);
    }
}

/* not static -- it's needed by src/HTMLView.cpp ; BrowserFrame.cpp */
void
fe_home_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  URL_Struct *url;
  MWContext *context = (MWContext *) closure;
  fe_UserActivity (context);
  if (!fe_globalPrefs.home_document || !*fe_globalPrefs.home_document)
    {
      XClearArea (XtDisplay (CONTEXT_WIDGET (context)),
		  XtWindow (CONTEXT_DATA (context)->drawing_area), 
		  0, 0,
		  CONTEXT_DATA (context)->scrolled_width,
		  CONTEXT_DATA (context)->scrolled_height, 
		  False);
      FE_Alert (context, fe_globalData.no_home_url_message);
      return;
    }
  url = NET_CreateURLStruct (fe_globalPrefs.home_document, FALSE);
  fe_GetURL ((MWContext *) closure, url, FALSE);
}

/* Help menu
 */
void
fe_about_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;

  fe_UserActivity (context);

  fe_reuseBrowser(context, NET_CreateURLStruct ("about:", FALSE));
}

void
fe_manual_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  char* url;
  char buf[1024], *in, *out;

  fe_UserActivity (context);

  url = HTTP_MANUAL;

  if ( url ) {
	for (in = url, out = buf; *in; in++, out++) *out = *in - HTTP_OFF;
	*out = 0;
	
	fe_reuseBrowser(context, NET_CreateURLStruct (buf, FALSE));
  }
}

#ifdef X_PLUGINS
void
fe_aboutPlugins_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  fe_UserActivity (context);
  fe_GetURL (context, NET_CreateURLStruct ("about:plugins", FALSE), FALSE);
}
#endif /* X_PLUGINS */

void
fe_aboutFonts_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  fe_UserActivity (context);
  fe_GetURL (context, NET_CreateURLStruct ("about:fonts", FALSE), FALSE);
}

/* Message composition stuff. */

void
fe_mailcompose_obeycb(MWContext *context, fe_MailComposeCallback cbid,
			void *call_data)
{
    switch (cbid) {
	case ComposeClearAllText_cb: {
	    Widget text = CONTEXT_DATA (context)->mcBodyText;
	    fe_SetTextFieldAndCallBack(text, "");
	    break;
	}
	case ComposeSelectAllText_cb: {
	    Widget text = CONTEXT_DATA (context)->mcBodyText;
	    XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)
						call_data;
	    if (cb)
		XmTextSetSelection(text, 0, XmTextGetLastPosition(text),
					cb->event->xkey.time);
	    break;
	}
    default:
      XP_ASSERT (0);
      break;
    }
}

#if defined(MOZ_MAIL_NEWS) || defined(MOZ_MAIL_COMPOSE)
void
FE_InsertMessageCompositionText(MSG_Pane* comppane,
				const char* text,
				XP_Bool leaveCursorAtBeginning) {

  MWContext* context = MSG_GetContext(comppane);
  /* call - function defined in src/ComposeView.cpp */
  fe_InsertMessageCompositionText(context, text, leaveCursorAtBeginning);
  return;
}
#endif  /* MOZ_MAIL_NEWS || MOZ_MAIL_COMPOSE */

/* rlogin 
 */

void
FE_ConnectToRemoteHost (MWContext *context, int url_type, char *hostname,
			char *port, char *username)
{
  char *name;
  const char *command;
  const char *user_command;
  char *buf;
  const char *in;
  char *out;
  char **av, **ac, **ae;
  int na;
  Boolean cop_out_p = False;
  pid_t forked;

  switch (url_type)
    {
    case FE_TELNET_URL_TYPE:
      name = "telnet";
      command = fe_globalPrefs.telnet_command;
      user_command = 0 /* fe_globalPrefs.telnet_user_command */;
      break;
    case FE_TN3270_URL_TYPE:
      name = "tn3270";
      command = fe_globalPrefs.tn3270_command;
      user_command = 0 /* fe_globalPrefs.tn3270_user_command */;
      break;
    case FE_RLOGIN_URL_TYPE:
      name = "rlogin";
      command = fe_globalPrefs.rlogin_command;
      user_command = fe_globalPrefs.rlogin_user_command;
      break;
    default:
      abort ();
    }

  if (username && user_command && *user_command)
    command = user_command;
  else if (username)
    cop_out_p = True;

  buf = (char*) malloc( strlen(command) + 1
    + (hostname && *hostname ? strlen(hostname) : strlen("localhost"))
    + (username && *username ? strlen(username) : 0)
    + (port && *port ? strlen(port) : 0) );
  ac = av = (char**) malloc(10 * sizeof (char*));
  if (buf == NULL || av == NULL)
    goto malloc_lossage;
  ae = av + 10;
  in = command;
  *ac = out = buf;
  na = 0;
  while (*in)
    {
      if (*in == '%')
	{
	  in++;
	  if (*in == 'h')
	    {
	      char *s;
	      char *h = (hostname && *hostname ? hostname : "localhost");

	      /* Only allow the hostname to contain alphanumerics or
		 _ - and . to prevent people from embedding shell command
		 security holes in the host name. */
	      for (s = h; *s; s++)
		if (*s == '_' || (*s == '-' && s != h) || *s == '.' ||
		    isalpha(*s) || isdigit(*s))
		  *out++ = *s;
	    }
	  else if (*in == 'p')
	    {
	      if (port && *port)
		{
		  int port_num = atoi(port);

		  if (port_num > 0)
		    {
		      char buf1[6];
		      PR_snprintf (buf1, sizeof (buf1), "%.5u", port_num);
		      strcpy(out, buf1);
		      out += strlen(buf1);
		    }
		}
	    }
	  else if (*in == 'u')
	    {
	      char *s;
	      /* Only allow the user name to contain alphanumerics or
		 _ - and . to prevent people from embedding shell command
		 security holes in the host name. */
	      if (username && *username)
		{
		  for (s = username; *s; s++)
		    if (*s == '_' || (*s == '-' && s != username) ||
			*s == '.' || isalpha(*s) || isdigit(*s))
		      *out++ = *s;
		}
	    }
	  else if (*in == '%')
	    {
	      *out++ = '%';
	    }
	  else
	    {
	      char buf2 [255];
	      PR_snprintf (buf2, sizeof (buf2),
				 XP_GetString( XFE_UNKNOWN_ESCAPE_CODE ), name, *in);
	      FE_Alert (context, buf2);
	    }
	  if (*in)
	    in++;
	}
      else if (*in == ' ')
	{
	  if (out != *ac)
	    {
	      *out++ = '\0';
	      na++;
	      if (++ac == ae)
		{
		  av = (char**) realloc(av, (na + 10) * sizeof (char*));
		  if (av == NULL)
		    goto malloc_lossage;
		  ac = av + na;
		  ae = ac + 10;
		}
	      *ac = out;
	    }
	  in++;
	}
      else
	{
	  *out = *in;
	  out++;
	  in++;
	}
    }

  if (out != *ac)
    {
      *out = '\0';
      na++;
      ac++;
    }
  if (ac == ae)
    {
      av = (char**) realloc(av, (na + 1) * sizeof (char*));
      if (av == NULL)
	goto malloc_lossage;
      ac = av + na;
    }
  *ac = 0;

  if (cop_out_p)
    {
      char buf2 [1024];
      PR_snprintf (buf2, sizeof (buf2), XP_GetString(XFE_LOG_IN_AS), username);
      fe_Message (context, buf2);
    }

  switch (forked = fork ())
    {
    case -1:
      fe_perror (context, XP_GetString( XFE_COULDNT_FORK ) );
      break;
    case 0:
      {
	Display *dpy = XtDisplay (CONTEXT_WIDGET (context));
	close (ConnectionNumber (dpy));

	execvp (av [0], av);

	PR_snprintf (buf, sizeof (buf), XP_GetString( XFE_EXECVP_FAILED ),
			fe_progname, av[0]);
	perror (buf);
	exit (1);	/* Note that this only exits a child fork.  */
	break;
      }
    default:
      /* This is the "old" process (subproc pid is in `forked'.) */
      break;
    }
  free(av);
  free(buf);
  return;

malloc_lossage:
  if (av) free(av);
  if (buf) free(buf);
  fe_Message (context, XP_GetString(XFE_OUT_OF_MEMORY_URL));
}

/* The popup menu
 */

URL_Struct *fe_url_under_mouse = 0;
URL_Struct *fe_image_under_mouse = 0;

static void
fe_save_image_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  XmString xm_title = 0;
  char *title = 0;
  URL_Struct *url;

  fe_UserActivity (context);

  XtVaGetValues (widget, XmNlabelString, &xm_title, 0);
  XmStringGetLtoR (xm_title, XmFONTLIST_DEFAULT_TAG, &title);
  XmStringFree(xm_title);

  url =	fe_image_under_mouse;
  if (! url)
    FE_Alert (context, fe_globalData.not_over_image_message);
  if (title) free (title);
  if (url)
    fe_SaveURL (context, url);
  fe_image_under_mouse = 0; /* it will be freed in the exit routine. */
}


static void
fe_save_link_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  XmString xm_title = 0;
  char *title = 0;
  URL_Struct *url;

  fe_UserActivity (context);

  XtVaGetValues (widget, XmNlabelString, &xm_title, 0);
  XmStringGetLtoR (xm_title, XmFONTLIST_DEFAULT_TAG, &title);
  XmStringFree(xm_title);

  url =	fe_url_under_mouse;
  if (! url)
    FE_Alert (context, fe_globalData.not_over_link_message);
  if (title) free (title);
  if (url)
    fe_SaveURL (context, url);
  fe_url_under_mouse = 0; /* it will be freed in the exit routine. */
}

static void
fe_open_image_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  URL_Struct *url;
  fe_UserActivity (context);
  url =	fe_image_under_mouse;
  if (! url)
    FE_Alert (context, fe_globalData.not_over_image_message);
  else
    {
      fe_GetURL (XP_GetNonGridContext(context), url, FALSE);
      fe_image_under_mouse = 0; /* it will be freed in the exit routine. */
    }
}

static void
fe_clipboard_url_1 (Widget widget, XtPointer closure, XtPointer call_data,
					URL_Struct *url, char* html)
{
  MWContext *context = (MWContext *) closure;
  XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *) call_data;
  XEvent *event = (cb ? cb->event : 0);
  Time time = (event && (event->type == KeyPress ||
			 event->type == KeyRelease)
	       ? event->xkey.time :
	       event && (event->type == ButtonPress ||
			 event->type == ButtonRelease)
	       ? event->xbutton.time :
	       XtLastTimestampProcessed (XtDisplay(CONTEXT_WIDGET (context))));
  fe_UserActivity (context);

  if (! url)
    FE_Alert (context, fe_globalData.not_over_link_message);
  else
    {
		fe_OwnClipboard(widget, time,
						strdup (url->address), html, NULL, 0, False);
#ifdef NOT_rhess
		/*
		 * NOTE:  it's not really valid to make a primary selection if you
		 *        can't show the selection on the display...
		 *        [ this is a hidden selection ]
		 *
		 */
		fe_OwnPrimarySelection(widget, time, 
							   strdup (url->address), html, NULL, 0, context);
#endif
		NET_FreeURLStruct (url);
    }
}

static char fe_link_html_head[]   = "<A HREF=\"";
static char fe_link_html_middle[] = "\" >";
static char fe_link_html_tail[]   = "</A>";

static char fe_image_html_head[]  = "<IMG SRC=\"";
static char fe_image_html_tail[]  = "\" ALT=\"Image\" BORDER=0 >";

#define XFE_LINK_HTML_HEAD   (fe_link_html_head)
#define XFE_LINK_HTML_MIDDLE (fe_link_html_middle)
#define XFE_LINK_HTML_TAIL   (fe_link_html_tail)

#define XFE_IMAGE_HTML_HEAD  (fe_image_html_head)
#define XFE_IMAGE_HTML_TAIL  (fe_image_html_tail)

void
fe_clipboard_link_cb (Widget widget, XtPointer closure, 
					  XtPointer call_data,
					  URL_Struct *url)
{
	char *html = NULL;
	char *link = url->address;
	int32 len = strlen(link);
	char *head = XFE_LINK_HTML_HEAD;
	char *midd = XFE_LINK_HTML_MIDDLE;
	char *tail = XFE_LINK_HTML_TAIL;

	html = XP_ALLOC(len + len + 2 +
					strlen(head) + strlen(midd) + strlen(tail)
					);
	sprintf(html, "%s%s%s%s%s\0", head, link, midd, link, tail);

	fe_clipboard_url_1 (widget, closure, call_data, url, html);
	XP_FREE(html);
}

void
fe_clipboard_image_link_cb (Widget widget, XtPointer closure, 
							XtPointer call_data,
							URL_Struct *url, URL_Struct *img)
{
	char *html = NULL;
	char *link = url->address;
	int32 len = strlen(link);
	char *head = XFE_LINK_HTML_HEAD;
	char *midd = XFE_LINK_HTML_MIDDLE;
	char *tail = XFE_LINK_HTML_TAIL;

	if (!img) {
		html = XP_ALLOC(len + len + 2 +
						strlen(head) + strlen(midd) + strlen(tail)
						);
		sprintf(html, "%s%s%s%s%s\0", head, link, midd, link, tail);

		fe_clipboard_url_1 (widget, closure, call_data, url, html);
		XP_FREE(html);
	}
	else {
		char *image = img->address;
		char *ihead = XFE_IMAGE_HTML_HEAD;
		char *itail = XFE_IMAGE_HTML_TAIL;

		html = XP_ALLOC(len + 2 + strlen(image) +
						strlen(head) + strlen(midd) + strlen(tail) +
						strlen(ihead) + strlen(itail)
						);
		sprintf(html, "%s%s%s%s%s%s%s\0", 
				head, link, midd, ihead, image, itail, tail);

		fe_clipboard_url_1 (widget, closure, call_data, url, html);
		NET_FreeURLStruct (img);
	}
	XP_FREE(html);
}

void
fe_clipboard_image_cb (Widget widget, XtPointer closure, 
					   XtPointer call_data,
					   URL_Struct *url)
{
	char *html = NULL;
	char *link = url->address;
	int32 len = strlen(link);

	char *head = XFE_IMAGE_HTML_HEAD;
	char *tail = XFE_IMAGE_HTML_TAIL;

	html = XP_ALLOC(len + 2 + strlen(head) + strlen(tail));

	sprintf(html, "%s%s%s\0", head, link, tail);

	fe_clipboard_url_1 (widget, closure, call_data, url, html);
	XP_FREE(html);
}

/*
 * For scrolling the window with the arrow keys, we need to
 * insert a lookahead key eater into each action routine,
 * else it is possible to queue up too many key events, and
 * screw up our careful scroll/expose event timing.
 */
static void
fe_eat_window_key_events(Display *display, Window window)
{
  XEvent event;

  XSync(display, FALSE);
  while (XCheckTypedWindowEvent(display, window, KeyPress, &event) == TRUE);
}


static void
fe_column_forward_action (Widget widget, XEvent *event,
			  String *av, Cardinal *ac)
{
  XKeyEvent *kev = (XKeyEvent *)event;
  MWContext *context = fe_WidgetToMWContext (widget);
  XP_ASSERT (context);
  if (!context) return;

  fe_column_forward_cb (widget, (XtPointer)context, (XtPointer)0);
  fe_eat_window_key_events(XtDisplay(widget), kev->window);
}


static void
fe_column_backward_action (Widget widget, XEvent *event,
			  String *av, Cardinal *ac)
{
  XKeyEvent *kev = (XKeyEvent *)event;
  MWContext *context = fe_WidgetToMWContext (widget);
  XP_ASSERT (context);
  if (!context) return;

  fe_column_backward_cb (widget, (XtPointer)context, (XtPointer)0);
  fe_eat_window_key_events(XtDisplay(widget), kev->window);
}


static void
fe_line_forward_action (Widget widget, XEvent *event,
			  String *av, Cardinal *ac)
{
  XKeyEvent *kev = (XKeyEvent *)event;
  MWContext *context = fe_WidgetToMWContext (widget);
  XP_ASSERT (context);
  if (!context) return;

  fe_line_forward_cb (widget, (XtPointer)context, (XtPointer)0);
  fe_eat_window_key_events(XtDisplay(widget), kev->window);
}


static void
fe_line_backward_action (Widget widget, XEvent *event,
			  String *av, Cardinal *ac)
{
  XKeyEvent *kev = (XKeyEvent *)event;
  MWContext *context = fe_WidgetToMWContext (widget);
  XP_ASSERT (context);
  if (!context) return;

  fe_line_backward_cb (widget, (XtPointer)context, (XtPointer)0);
  fe_eat_window_key_events(XtDisplay(widget), kev->window);
}


/* Actions for use in translations tables. 
 */

#define DEFACTION(NAME) \
static void \
fe_##NAME##_action (Widget widget, XEvent *event, String *av, Cardinal *ac) \
{  \
  MWContext *context = fe_WidgetToMWContext (widget); \
  XP_ASSERT (context); \
  if (!context) return; \
  fe_##NAME##_cb (widget, (XtPointer)context, (XtPointer)0); \
}

/* DEFACTION (new) */
/*DEFACTION (open_url)*/
/*DEFACTION (open_file)*/
#ifdef EDITOR
/*DEFACTION (edit)*/
#endif /* EDITOR */
/*DEFACTION (save_as)*/
/*DEFACTION (mailto)*/
/*DEFACTION (print)*/
/* DEFACTION (docinfo) */
/*DEFACTION (delete)*/
/* DEFACTION (quit) */
/* DEFACTION (cut) */
/* DEFACTION (copy) */
/* DEFACTION (paste) */
/* DEFACTION (paste_quoted) */
/*DEFACTION (find)*/
/* DEFACTION (find_again) */
/* DEFACTION (reload) */
/* DEFACTION (load_images) */
/* DEFACTION (refresh) */
/* DEFACTION (view_source) */
/* DEFACTION (back) */
/* DEFACTION (forward) */
/* DEFACTION (history) */
/* DEFACTION (home) */
/*DEFACTION (save_options)*/
/* DEFACTION (view_bookmark) */
DEFACTION (fishcam)
DEFACTION (net_showstatus)
/* DEFACTION (abort) */
DEFACTION (page_forward)
DEFACTION (page_backward)
/*DEFACTION (line_forward)*/
/*DEFACTION (line_backward)*/
/*DEFACTION (column_forward)*/
/*DEFACTION (column_backward)*/

DEFACTION (save_image)
DEFACTION (open_image)
DEFACTION (save_link)
/*DEFACTION (follow_link)*/
/*DEFACTION (follow_link_new)*/
#undef DEFACTION

static void
fe_open_url_action (Widget widget, XEvent *event, String *av, Cardinal *ac)
{
  /* openURL() pops up a file requestor.
     openURL(http:xxx) opens that URL.
     Really only one arg is meaningful, but we also accept the form
     openURL(http:xxx, remote) for the sake of remote.c, and treat
     openURL(remote) the same as openURL().
   */
  MWContext *context = fe_WidgetToMWContext (widget);
  MWContext *old_context = NULL;
  Boolean other_p = False;
  char *windowName = 0;
  XP_ASSERT (context);
  if (!context) return;
  context = XP_GetNonGridContext (context);
  fe_UserActivity (context);

  if (*ac && av[*ac-1] && !strcmp (av[*ac-1], "<remote>"))
    (*ac)--;

  if (*ac > 1 && av[*ac-1] )
  {
     if ( 
      (!strcasecomp (av[*ac-1], "new-window") ||
       !strcasecomp (av[*ac-1], "new_window") ||
       !strcasecomp (av[*ac-1], "newWindow") ||
       !strcasecomp (av[*ac-1], "new")))
    {
      other_p = True;
      (*ac)--;
    }
    else if ( (old_context = XP_FindNamedContextInList(context, av[*ac-1])))
    {
	context = old_context;
	other_p = False;
        (*ac)--;
    }
    else 
    {
	StrAllocCopy(windowName, av[*ac-1]);
	other_p = True;
        (*ac)--;
    }

   }

  if (*ac == 1 && av[0])
    {
      URL_Struct *url_struct = NET_CreateURLStruct (av[0], FALSE);

#if defined(MOZ_MAIL_NEWS) || defined(MOZ_MAIL_COMPOSE)
      /* Dont create new windows for Compose. fe_GetURL will take care of it */
      if (MSG_RequiresComposeWindow(url_struct->address))
	other_p = False;
#endif

      if (other_p)
      {
	context = fe_MakeWindow (XtParent (CONTEXT_WIDGET (context)),
		       context, url_struct, windowName, 
			MWContextBrowser, FALSE);
        XP_FREE(windowName);
      }
      else
	fe_GetURL (context, url_struct, FALSE);
    }
  else if (*ac > 1)
    {
      fprintf (stderr, 
	       XP_GetString(XFE_COMMANDS_OPEN_URL_USAGE),
	       fe_progname);
    }
  else
    {
      fe_open_url_cb (widget, (XtPointer)context, (XtPointer)0);
    }
}

static void
fe_print_remote_action (Widget widget, XEvent *event, String *av, Cardinal *ac)
{
  /* Silent print for remote. Valid invocations are
     print(filename, remote)           : print URL of context to filename
     print(remote)                     : print URL of context to printer
     print(remote)                     : print URL of context to printer
  */
  MWContext *context = fe_WidgetToMWContext (widget);
  URL_Struct *url_struct = NULL;
  Boolean toFile = False;
  char *filename = NULL;

  XP_ASSERT (context);
  if (!context) return;
  fe_UserActivity (context);

  if (*ac && av[*ac-1] && !strcmp (av[*ac-1], "<remote>"))
    (*ac)--;
  else
    return;    /* this is valid only for remote */

  if (*ac && av[*ac-1]) {
    filename = av[*ac-1];
    if (*filename) toFile = True;
    (*ac)--;
  }

  if (*ac > 0)
    fprintf (stderr, "%s: usage: print([filename])\n", fe_progname);

  url_struct = SHIST_CreateWysiwygURLStruct (context,
                                       SHIST_GetCurrent (&context->hist));

  if (url_struct)
    {
      if (!toFile || filename)
    fe_Print(context, url_struct, toFile, filename);
      else
        NET_FreeURLStruct (url_struct);
    }
}

#if defined(MOZ_MAIL_NEWS) || defined(MOZ_MAIL_COMPOSE)
static void
fe_mailto_action (Widget widget, XEvent *event, String *av, Cardinal *ac)
{
  /* see also fe_open_url_action()

     #### This really ought to be implemented by opening a "mailto:" URL,
     instead of by calling MSG_ComposeMessage -- that'd be more abstract
     and stuff.  -jwz
   */

  MWContext *context = fe_WidgetToMWContext (widget);
  XP_ASSERT (context);
  if (!context) return;
  fe_UserActivity (context);
  if (*ac && av[*ac-1] && !strcmp (av[*ac-1], "<remote>"))
    (*ac)--;
  if (*ac >= 1)
    {
      char *to;
      int size = 0;
      int i;
      for (i = 0; i < *ac; i++)
	size += (strlen (av[i]) + 2);
      to = (char *) malloc (size + 1);
      *to = 0;
      for (i = 0; i < *ac; i++)
	{
	  strcat (to, av[i]);
	  if (i < (*ac)-1)
	    strcat (to, ", ");
	}

      MSG_ComposeMessage (context,
			  0, /* from */
			  0, /* reply_to */
			  to,
			  0, /* cc */
			  0, /* bcc */
			  0, /* fcc */
			  0, /* newsgroups */
			  0, /* followup_to */
			  0, /* organization */
			  0, /* subject */
			  0, /* references */
			  0, /* other_random_headers */
			  0, /* priority */
			  0, /* attachment */
			  0, /* newspost_url */
			  0, /* body */
			  FALSE, /* force_plain_text */
			  0 /* html_part */
			  );
    }
  else if (*ac > 1)
    {
      fprintf (stderr, 
			   XP_GetString(XFE_COMMANDS_MAIL_TO_USAGE),
			   fe_progname);
    }
  else
    {
      fe_mailto_cb (widget, (XtPointer)context, (XtPointer)0);
    }
}
#endif  /* MOZ_MAIL_NEWS || MOZ_MAIL_COMPOSE */

static void
fe_html_help_action (Widget widget, XEvent *event, String *av, Cardinal *ac)
{
  MWContext *context = fe_WidgetToMWContext (widget);
  XP_Bool remote_p = False;
  char *map_file_url;
  char *id;
  char *search_text;

  XP_ASSERT (context);
  if (!context) return;
  fe_UserActivity (context);
  if (*ac && av[*ac-1] && !strcmp (av[*ac-1], "<remote>")) {
    remote_p = True;
    (*ac)--;
  }

  if (*ac == 3) {
    map_file_url = av[0];
    id = av[1];
    search_text = av[2];
    NET_GetHTMLHelpFileFromMapFile(context, map_file_url, id, search_text);
  }
  else {
      fprintf (stderr,
			   XP_GetString(XFE_COMMANDS_HTML_HELP_USAGE),
			   fe_progname);
  }
}


static void
fe_deleteKey_action (Widget widget, XEvent *event, String *av, Cardinal *ac)
{
  MWContext *context = fe_WidgetToMWContext (widget);

  XP_ASSERT(context);
  if (!context) return;

#ifdef MOZ_MAIL_NEWS
  if (context->type == MWContextMail || context->type == MWContextNews)
    XP_ASSERT(0);
  else
#endif  /* MOZ_MAIL_NEWS */
    fe_page_backward_action(widget, event, av, ac);
}

static void
fe_undefined_key_action (Widget widget, XEvent *event,
			 String *av, Cardinal *ac)
{
  XBell (XtDisplay (widget), 0);
}

/* for the rest, look in src/Command.cpp -- for 'cmd_mapping mapping[]' */
XtActionsRec fe_CommandActions [] =
{
#if defined(MOZ_MAIL_NEWS) || defined(MOZ_MAIL_COMPOSE)
  { "mailto",		fe_mailto_action },
#endif

  { "print",        fe_print_remote_action },
  { "fishcam",		fe_fishcam_action	},
  { "net_showstatus",	fe_net_showstatus_action	},
  { "PageDown",		fe_page_forward_action	},
  { "PageUp",		fe_page_backward_action	},
  { "LineDown",		fe_line_forward_action	},
  { "LineUp",		fe_line_backward_action	},
  { "ColumnLeft",	fe_column_forward_action  },
  { "ColumnRight",	fe_column_backward_action },

  { "Delete",		fe_deleteKey_action },
  { "Backspace",	fe_deleteKey_action },

  { "SaveImage",	fe_save_image_action },
  { "OpenImage",	fe_open_image_action },
  { "SaveURL",		fe_save_link_action },
  { "OpenURL",		fe_open_url_action },
  { "OpenURLNewWindow",	fe_open_url_action },

  /* For Html Help */
  { "htmlHelp",		fe_html_help_action },

  { "undefined-key",	fe_undefined_key_action }
};

int fe_CommandActionsSize = countof (fe_CommandActions);

/**************************/
/* MessageCompose actions */
/* (Mail/News actions are */
/* defined in mailnews.c) */
/**************************/


void
fe_InitCommandActions ()
{
  XtAppAddActions(fe_XtAppContext, fe_CommandActions, fe_CommandActionsSize);
}


/* This installs all the usual translations on widgets which are a part
   of the main Netscape window -- it recursively decends the tree, 
   installing the appropriate translations everywhere.  This should
   not be called on popups/transients, but only on widgets which are
   children of the main Shell.
 */
void
fe_HackTranslations (MWContext *context, Widget widget)
{
  XtTranslations global_translations = 0;
  XtTranslations secondary_translations = 0;
  XP_Bool has_display_area = FALSE;

  if (XmIsGadget (widget))
    return;

 /* To prevent focus problems, dont enable translations on the menubar
    and its children. The problem was that when we had the translations
    in the menubar too, we could do a translation and popup a modal
    dialog when one of the menu's from the menubar was pulleddown. Now
    motif gets too confused about who holds pointer and keyboard focus.
 */

  if (XmIsRowColumn(widget)) {
    unsigned char type;
    XtVaGetValues(widget, XmNrowColumnType, &type, 0);
    if (type == XmMENU_BAR)
      return;
  }

  switch (context->type)
    {
#ifdef EDITOR
    case MWContextEditor:
      has_display_area = FALSE;
      global_translations    = fe_globalData.global_translations;
      secondary_translations = fe_globalData.editor_global_translations;
      break;
#endif /*EDITOR*/

    case MWContextBrowser:
      has_display_area = TRUE;
      global_translations    = fe_globalData.global_translations;
      secondary_translations = fe_globalData.browser_global_translations;
      break;

    case MWContextMail:
    case MWContextNews:
      has_display_area = TRUE;
      global_translations    = fe_globalData.global_translations;
      secondary_translations = fe_globalData.mailnews_global_translations;
      break;

    case MWContextMailMsg:
      has_display_area = TRUE;
      global_translations    = fe_globalData.global_translations;
      secondary_translations = fe_globalData.messagewin_global_translations;
      break;

    case MWContextMessageComposition:
      has_display_area = FALSE;
      global_translations    = fe_globalData.global_translations;
      secondary_translations = fe_globalData.mailcompose_global_translations;
      break;

    case MWContextAddressBook:
      has_display_area = FALSE;
      global_translations    = fe_globalData.global_translations;
      secondary_translations = fe_globalData.ab_global_translations;
      break;
    case MWContextDialog:
      has_display_area = TRUE;
      /*global_translations = 0;*/
      /*secondary_translations = fe_globalData.dialog_global_translations;*/
      global_translations    = fe_globalData.global_translations;
      secondary_translations = fe_globalData.browser_global_translations;
      break;
    case MWContextPane:  /*context used by navcenter right now */
      global_translations    = fe_globalData.global_translations;
      secondary_translations = fe_globalData.navcenter_global_translations;
    default:
      break;
  }
  if (!XP_STRCMP( XtName(widget), "editorDrawingArea" )) {
      XtOverrideTranslations (widget, fe_globalData.global_translations);
      XtOverrideTranslations (widget, fe_globalData.editor_global_translations);
  } else {
      if (global_translations)
          XtOverrideTranslations (widget, global_translations);
      if (secondary_translations)
          XtOverrideTranslations (widget, secondary_translations);
  }

  if (XmIsTextField (widget) || XmIsText (widget) || XmIsList(widget))
    {
      /* Set up the editing translations (all text fields, everywhere.) */
      if (XmIsTextField (widget) || XmIsText (widget))
	fe_HackTextTranslations (widget);

      /* Install globalTextFieldTranslations on single-line text fields in
	 windows which have an HTML display area (browser, mail, news) but
	 not in windows which don't have one (compose, download, bookmarks,
	 address book...)
       */
      if (has_display_area &&
	  XmIsTextField (widget) &&
	  fe_globalData.global_text_field_translations)
	XtOverrideTranslations (widget,
				fe_globalData.global_text_field_translations);
   }
  else
   {
       Widget *kids = 0;
       Cardinal nkids = 0;

      /* Not a Text or TextField.
       */
      /* Install globalNonTextTranslations on non-text widgets in windows which
	 have an HTML display area (browser, mail, news, view source) but not
	 in windows which don't have one (compose, download, bookmarks,
	 address book...)
       */
      if (has_display_area &&
	  fe_globalData.global_nontext_translations)
	XtOverrideTranslations (widget,
				fe_globalData.global_nontext_translations);

      /* Now recurse on the children.
       */
      XtVaGetValues (widget, XmNchildren, &kids, XmNnumChildren, &nkids, 0);
      while (nkids--)
	  fe_HackTranslations (context, kids [nkids]);
    }
}

/* This installs all the usual translations on Text and TextField widgets.
 */
void
fe_HackTextTranslations (Widget widget)
{ 
  Widget parent = widget;

  for (parent=widget; parent && !XtIsWMShell (parent); parent=XtParent(parent))
    if (XmLIsGrid(parent))
      /* We shouldn't be messing with Grid widget and its children */
      return;

  if (XmIsTextField(widget))
    {
      if (fe_globalData.editing_translations)
	XtOverrideTranslations (widget, fe_globalData.editing_translations);
      if (fe_globalData.single_line_editing_translations)
	XtOverrideTranslations (widget,
			      fe_globalData.single_line_editing_translations);
    }
  else if (XmIsText(widget))
    {
      if (fe_globalData.editing_translations)
	XtOverrideTranslations (widget, fe_globalData.editing_translations);
      if (fe_globalData.multi_line_editing_translations)
	XtOverrideTranslations (widget,
			      fe_globalData.multi_line_editing_translations);
    }
  else
    {
      XP_ASSERT(0);
    }
}

void
fe_HackFormTextTranslations(Widget widget)
{
  Widget parent = widget;

  for (parent=widget; parent && !XtIsWMShell (parent); parent=XtParent(parent))
    if (XmLIsGrid(parent))
      /* We shouldn't be messing with Grid widget and its children */
      return;

  if ((XmIsTextField(widget)) || (XmIsText(widget)) )
    {
      if (fe_globalData.form_elem_editing_translations)
	XtOverrideTranslations (widget, fe_globalData.form_elem_editing_translations);
    }
  else
    {
      XP_ASSERT(0);
    }
}


/* This installs all the usual translations for popups/transients.
   All it does is recurse the tree and call fe_HackTextTranslations
   on any Text or TextField widgets it finds.
 */
void
fe_HackDialogTranslations (Widget widget)
{
  if (XmIsGadget (widget))
    return;
  else if (XmIsText (widget) || XmIsTextField (widget))
    fe_HackTextTranslations (widget);
  else
    {
      Widget *kids = 0;
      Cardinal nkids = 0;
      XtVaGetValues (widget, XmNchildren, &kids, XmNnumChildren, &nkids, 0);
      while (nkids--)
	fe_HackDialogTranslations (kids [nkids]);
    }
}

/* these two are now in src/DownloadFrame.cpp */
extern NET_StreamClass *fe_MakeSaveAsStream (int format_out, void *data_obj,
											 URL_Struct *url_struct, MWContext *context);

extern NET_StreamClass *fe_MakeSaveAsStreamNoPrompt (int format_out, void *data_obj,
													 URL_Struct *url_struct, MWContext *context);

/*
 * parse_extensions
 * Give a comma separated string of extensions, fills in the array of
 * character strings in NET_cdataStruct.
 * eg, "cpp,cc" becomes:
 * mimetype_entry->exts[0] = "cpp";
 * mimetype_entry->exts[1] = "cc";
 * mimetype_entry->exts[2] = NULL;
 */
static void
parse_extensions(NET_cdataStruct* mimetype_entry, char* exts)
{
	int i;
	char* p;

	XP_ASSERT(mimetype_entry && exts);

	mimetype_entry->num_exts = 0;
	for ( p = exts; p && *p; p = strchr(p, ',') ) {
		if ( *p == ',' ) p++;
		mimetype_entry->num_exts++;
	}

	mimetype_entry->exts = (char**) malloc(sizeof(char*) * (mimetype_entry->num_exts+1));
	if ( mimetype_entry->exts == NULL ) return;

	for ( i = 0, p = exts; p && *p; p = strchr(p, ','), i++ ) {
		if ( *p == ',' ) p++;
		mimetype_entry->exts[i] = strdup(p);
		if ( strchr(mimetype_entry->exts[i], ',') ) *strchr(mimetype_entry->exts[i], ',') = '\0';
	}
	mimetype_entry->exts[i] = NULL;
}


/*
 * add_pref_mime_type
 * Given the beginning of a mimetype preference, registers that
 * mimetype handler with netlib.
 */
static void
add_pref_mime_type(char* name)
{
	char buf[1024];
	int32 load_action;
	char* extension = NULL;
	char* contenttype = NULL;
	char* command = NULL;
	char* description = NULL;
	NET_cdataStruct* mimetype_entry = NULL;
	NET_mdataStruct* mailcap_entry = NULL;

	strcpy(buf, name); strcat(buf, ".mimetype");
	if ( PREF_CopyCharPref(buf, &contenttype) != PREF_OK ) goto failed;

	strcpy(buf, name); strcat(buf, ".extension");
	if ( PREF_CopyCharPref(buf, &extension) != PREF_OK ) goto failed;

	strcpy(buf, name); strcat(buf, ".load_action");
	if ( PREF_GetIntPref(buf, &load_action) != PREF_OK ) goto failed;

	strcpy(buf, name); strcat(buf, ".unix_appname");
	if ( PREF_CopyCharPref(buf, &command) != PREF_OK ) goto failed;

	strcpy(buf, name); strcat(buf, ".description");
	if ( PREF_CopyCharPref(buf, &description) != PREF_OK ) goto failed;

	mailcap_entry = NET_mdataCreate();
	mimetype_entry = NET_cdataCreate();

	mailcap_entry->contenttype = strdup(contenttype);
	mailcap_entry->command = command ? strdup(command) : NULL;
	mailcap_entry->xmode = (load_action == 1) ? 
							strdup(NET_COMMAND_SAVE_TO_DISK) :
							(load_action == 3) ?
							strdup(NET_COMMAND_UNKNOWN) :
							(load_action == 4) ?
							strdup(NET_COMMAND_PLUGIN) : NULL;

	mimetype_entry->ci.type = contenttype ? strdup(contenttype) : NULL;
	mimetype_entry->ci.desc = description ? strdup(description) : NULL;
	mimetype_entry->pref_name = strdup(name);

	parse_extensions(mimetype_entry, extension);

	if ( mailcap_entry->xmode == NULL && 
		 mailcap_entry->command && 
		 *(mailcap_entry->command) &&
		 strcasecmp(mailcap_entry->contenttype, TEXT_HTML) &&
		 strcasecmp(mailcap_entry->contenttype, MESSAGE_RFC822) &&
		 strcasecmp(mailcap_entry->contenttype, MESSAGE_NEWS) ) {
		NET_RegisterExternalViewerCommand(mailcap_entry->contenttype, mailcap_entry->command, mailcap_entry->stream_buffer_size);	
	}

	NET_cdataAdd(mimetype_entry);
	NET_mdataAdd(mailcap_entry);

	if ( extension ) XP_FREE(extension);
	if ( contenttype ) XP_FREE(contenttype);
	if ( description ) XP_FREE(description);
	if ( command ) XP_FREE(command);
	return;

failed:
	if ( extension ) XP_FREE(extension);
	if ( contenttype ) XP_FREE(contenttype);
	if ( description ) XP_FREE(description);
	if ( command ) XP_FREE(command);
	if ( mimetype_entry ) NET_cdataFree(mimetype_entry);
	if ( mailcap_entry ) NET_mdataFree(mailcap_entry);
}


/*
 * fe_RegisterPrefConverters
 * Registers the mimetype converters that are specified by the
 * preferences.
 */
void
fe_RegisterPrefConverters(void)
{
	extern FILE* real_stderr;
	char* children = NULL;
	char* child = NULL;
	int index = 0;

	if ( PREF_CreateChildList("mime", &children) != PREF_OK ) {
		return;
	}

	while ( (child = PREF_NextChild(children, &index)) != NULL ) {
		add_pref_mime_type(child);
	}

	XP_FREE(children);
}


void
fe_RegisterConverters (void)
{
#ifdef NEW_DECODERS
  NET_ClearAllConverters ();
#endif /* NEW_DECODERS */

  if (fe_encoding_extensions)
    {
      int i = 0;
      while (fe_encoding_extensions [i])
	free (fe_encoding_extensions [i++]);
      free (fe_encoding_extensions);
      fe_encoding_extensions = 0;
    }

  /* register X specific decoders
   */
  if (fe_globalData.encoding_filters)
    {
      char *copy = strdup (fe_globalData.encoding_filters);
      char *rest = copy;
      char *end = rest + strlen (rest);

      int exts_count = 0;
      int exts_size = 10;
      char **all_exts = (char **) malloc (sizeof (char *) * exts_size);

      while (rest < end)
	{
	  char *start;
	  char *eol, *colon;
	  char *input, *output, *extensions, *command;
	  eol = strchr (rest, '\n');
	  if (eol) *eol = 0;

	  rest = fe_StringTrim (rest);
	  if (! *rest)
	    /* blank lines are ok */
	    continue;

	  start = rest;

	  colon = strchr (rest, ':');
	  if (! colon) goto LOSER;
	  *colon = 0;
	  input = fe_StringTrim (rest);
	  rest = colon + 1;

	  colon = strchr (rest, ':');
	  if (! colon) goto LOSER;
	  *colon = 0;
	  output = fe_StringTrim (rest);
	  rest = colon + 1;

	  colon = strchr (rest, ':');
	  if (! colon) goto LOSER;
	  *colon = 0;
	  extensions = fe_StringTrim (rest);
	  rest = colon + 1;

	  command = fe_StringTrim (rest);
	  rest = colon + 1;
	  
	  if (*command)
	    {
	      /* First save away the extensions. */
	      char *rest = extensions;
	      while (*rest)
		{
		  char *start;
		  char *comma, *end;
		  while (isspace (*rest))
		    rest++;
		  start = rest;
		  comma = XP_STRCHR (start, ',');
		  end = (comma ? comma - 1 : start + strlen (start));
		  while (end >= start && isspace (*end))
		    end--;
		  if (comma) end++;
		  if (start < end)
		    {
		      all_exts [exts_count] =
			(char *) malloc (end - start + 1);
		      strncpy (all_exts [exts_count], start, end - start);
		      all_exts [exts_count][end - start] = 0;
		      if (++exts_count == exts_size)
			all_exts = (char **)
			  realloc (all_exts,
				   sizeof (char *) * (exts_size += 10));
		    }
		  rest = (comma ? comma + 1 : end);
		}
	      all_exts [exts_count] = 0;
	      fe_encoding_extensions = all_exts;

	      /* Now register the converter. */
	      NET_RegisterExternalDecoderCommand (input, output, command);
	    }
	  else
	    {
	  LOSER:
	      fprintf (stderr,
				   XP_GetString(XFE_COMMANDS_UNPARSABLE_ENCODING_FILTER_SPEC),
				   fe_progname, start);
	    }
	  rest = (eol ? eol + 1 : end);
	}
      free (copy);
    }

  /* Register standard decoders
     This must come AFTER all calls to NET_RegisterExternalDecoderCommand(),
     (at least in the `NEW_DECODERS' world.)
   */
  NET_RegisterMIMEDecoders ();

  /* How to save to disk. */
  NET_RegisterContentTypeConverter ("*", FO_SAVE_AS, NULL,
				    fe_MakeSaveAsStream);

  /* Saving any binary format as type `text' should save as `source' instead.
   */
  NET_RegisterContentTypeConverter ("*", FO_SAVE_AS_TEXT, NULL,
				    fe_MakeSaveAsStreamNoPrompt);
  NET_RegisterContentTypeConverter ("*", FO_QUOTE_MESSAGE, NULL,
				    fe_MakeSaveAsStreamNoPrompt);

  /* default presentation converter - offer to save unknown types. */
  NET_RegisterContentTypeConverter ("*", FO_PRESENT, NULL,
				    fe_MakeSaveAsStream);

#if 0
  NET_RegisterContentTypeConverter ("*", FO_VIEW_SOURCE, NULL,
				    fe_MakeViewSourceStream);
#endif

#ifndef NO_MOCHA_CONVERTER_HACK
  /* libmocha:LM_InitMocha() installs this convert. We blow away all
   * converters that were installed and hence these mocha default converters
   * dont get recreated. And mocha has no call to re-register them.
   * So this hack. - dp/brendan
   */
  NET_RegisterContentTypeConverter(APPLICATION_JAVASCRIPT, FO_PRESENT, 0,
				   NET_CreateMochaConverter);
#endif /* NO_MOCHA_CONVERTER_HACK */

  /* Parse stuff out of the .mime.types and .mailcap files.
   * We dont have to check dates of files for modified because all that
   * would have been done by the caller. The only place time checking
   * happens is
   * (1) Helperapp page is created
   * (2) Helpers are being saved (OK button pressed on the General Prefs).
   */
  NET_InitFileFormatTypes (fe_globalPrefs.private_mime_types_file,
			   fe_globalPrefs.global_mime_types_file);
  fe_isFileChanged(fe_globalPrefs.private_mime_types_file, 0,
		   &fe_globalData.privateMimetypeFileModifiedTime);

  NET_RegisterConverters (fe_globalPrefs.private_mailcap_file,
			  fe_globalPrefs.global_mailcap_file);
  fe_isFileChanged(fe_globalPrefs.private_mailcap_file, 0,
		   &fe_globalData.privateMailcapFileModifiedTime);

  fe_RegisterPrefConverters();

#ifndef NO_WEB_FONTS
  /* Register webfont converters */
  NF_RegisterConverters();
#endif /* NO_WEB_FONTS */

  /* Plugins go on top of all this */
  fe_RegisterPluginConverters();
}

/* The Windows menu in the toolbar */

static void
fe_switch_context_cb (Widget widget, XtPointer closure, XtPointer call_data)
{
  MWContext *context = (MWContext *) closure;
  struct fe_MWContext_cons *cntx = fe_all_MWContexts;

  /* We need to watchout here. If we were holding down the menu and
   * before we select, a context gets destroyed (ftp is done say), then
   * selecting on that item would give an invalid context here. Guard
   * against that case by validating the context.
   */
  
  while (cntx && (cntx->context != context))
    cntx = cntx->next;
  if (!cntx)
    /* Ah ha! invalid context. I told you! */
    return;
  
  XMapRaised(XtDisplay(CONTEXT_WIDGET(context)),
		   XtWindow(CONTEXT_WIDGET(context)));
  return;
}

void 
fe_SetString(Widget widget, const char* propname, char* str)
{
  XmString xmstr;
  xmstr = XmStringCreate(str, XmFONTLIST_DEFAULT_TAG);
  XtVaSetValues(widget, propname, xmstr, 0);
  XmStringFree(xmstr);
}

